char *zSql; /* SQL statement passed to declare_vtab() */
char *zCols; /* List of user defined columns */
+ sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+
/* Create a list of user columns for the virtual table */
zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
for(i=1; zCols && i<p->nColumn; i++){
static void fts3DeleteTerms(
int *pRC, /* Result code */
Fts3Table *p, /* The FTS table to delete from */
- sqlite3_value **apVal, /* apVal[] contains the docid to be deleted */
+ sqlite3_value *pRowid, /* The docid to be deleted */
u32 *aSz /* Sizes of deleted document written here */
){
int rc;
sqlite3_stmt *pSelect;
if( *pRC ) return;
- rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, apVal);
+ rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pSelect) ){
int i;
** The first value in the apVal[] array is assumed to contain an integer.
** This function tests if there exist any documents with docid values that
** are different from that integer. i.e. if deleting the document with docid
-** apVal[0] would mean the FTS3 table were empty.
+** pRowid would mean the FTS3 table were empty.
**
** If successful, *pisEmpty is set to true if the table is empty except for
-** document apVal[0], or false otherwise, and SQLITE_OK is returned. If an
+** document pRowid, or false otherwise, and SQLITE_OK is returned. If an
** error occurs, an SQLite error code is returned.
*/
-static int fts3IsEmpty(Fts3Table *p, sqlite3_value **apVal, int *pisEmpty){
+static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){
sqlite3_stmt *pStmt;
int rc;
- rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, apVal);
+ rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pStmt) ){
*pisEmpty = sqlite3_column_int(pStmt, 0);
return SQLITE_OK;
}
+/*
+** SQLite value pRowid contains the rowid of a row that may or may not be
+** present in the FTS3 table. If it is, delete it and adjust the contents
+** of subsiduary data structures accordingly.
+*/
+static int fts3DeleteByRowid(
+ Fts3Table *p,
+ sqlite3_value *pRowid,
+ int *pnDoc,
+ int *aSzDel
+){
+ int isEmpty = 0;
+ int rc = fts3IsEmpty(p, pRowid, &isEmpty);
+ if( rc==SQLITE_OK ){
+ if( isEmpty ){
+ /* Deleting this row means the whole table is empty. In this case
+ ** delete the contents of all three tables and throw away any
+ ** data in the pendingTerms hash table. */
+ rc = fts3DeleteAll(p);
+ *pnDoc--;
+ }else{
+ sqlite3_int64 iRemove = sqlite3_value_int64(pRowid);
+ rc = fts3PendingTermsDocid(p, iRemove);
+ fts3DeleteTerms(&rc, p, pRowid, aSzDel);
+ fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
+ if( sqlite3_changes(p->db) ) *pnDoc--;
+ if( p->bHasDocsize ){
+ fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
+ }
+ }
+ }
+
+ return rc;
+}
/*
** This function does the work for the xUpdate method of FTS3 virtual
u32 *aSzIns; /* Sizes of inserted documents */
u32 *aSzDel; /* Sizes of deleted documents */
int nChng = 0; /* Net change in number of documents */
+ int bInsertDone = 0;
+ int bReplace = 0; /* True if on conflict mode is REPLACE */
assert( p->pSegments==0 );
+ /* Check for a "special" INSERT operation. One of the form:
+ **
+ ** INSERT INTO xyz(xyz) VALUES('command');
+ */
+ if( nArg>1
+ && sqlite3_value_type(apVal[0])==SQLITE_NULL
+ && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL
+ ){
+ return fts3SpecialInsert(p, apVal[p->nColumn+2]);
+ }
+
/* Allocate space to hold the change in document sizes */
aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 );
if( aSzIns==0 ) return SQLITE_NOMEM;
aSzDel = &aSzIns[p->nColumn+1];
memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2);
- /* If this is a DELETE or UPDATE operation, remove the old record. */
- if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
- int isEmpty = 0;
- rc = fts3IsEmpty(p, apVal, &isEmpty);
- if( rc==SQLITE_OK ){
- if( isEmpty ){
- /* Deleting this row means the whole table is empty. In this case
- ** delete the contents of all three tables and throw away any
- ** data in the pendingTerms hash table.
- */
- rc = fts3DeleteAll(p);
+ /* If this is an INSERT operation, or an UPDATE that modifies the rowid
+ ** value, then this operation requires constraint handling.
+ **
+ ** 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 ){
+ sqlite3_int64 iNewRowid;
+ 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)
+ )){
+ if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){
+ rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel);
}else{
- isRemove = 1;
- iRemove = sqlite3_value_int64(apVal[0]);
- rc = fts3PendingTermsDocid(p, iRemove);
- fts3DeleteTerms(&rc, p, apVal, aSzDel);
- fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, apVal);
- if( p->bHasDocsize ){
- fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, apVal);
- }
- nChng--;
+ rc = fts3InsertData(p, apVal, pRowid);
+ bInsertDone = 1;
}
}
- }else if( sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){
+ }
+ if( rc!=SQLITE_OK ){
sqlite3_free(aSzIns);
- return fts3SpecialInsert(p, apVal[p->nColumn+2]);
+ return rc;
+ }
+
+ /* If this is a DELETE or UPDATE operation, remove the old record. */
+ if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
+ assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER );
+ rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel);
+ isRemove = 1;
+ iRemove = sqlite3_value_int64(apVal[0]);
}
/* If this is an INSERT or UPDATE operation, insert the new record. */
if( nArg>1 && rc==SQLITE_OK ){
- rc = fts3InsertData(p, apVal, pRowid);
+ if( bInsertDone==0 ){
+ rc = fts3InsertData(p, apVal, pRowid);
+ if( rc==SQLITE_CONSTRAINT ) rc = SQLITE_CORRUPT;
+ }
if( rc==SQLITE_OK && (!isRemove || *pRowid!=iRemove) ){
rc = fts3PendingTermsDocid(p, *pRowid);
}
-C Disable\sthe\stransfer\soptimization\sif\sthe\sdestination\stable\scontains\nany\sforeign\skey\sconstraint\sand\sforeign\skey\sconstraints\sare\senabled.\nTicket\s[6284df89debdf].
-D 2011-04-24T22:56:07.596
+C Add\ssupport\sfor\son\sconflict\sclauses\sto\sfts3/fts4.
+D 2011-04-25T18:49:57.773
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c 5653c5654ac9b65bf3646af7e1d695c7e9b991a0
+F ext/fts3/fts3.c 94fa15fc9d6290e2ba042c24fc83e272c86a40c6
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h 945926ea4b6a686c3e9834640a252d9870b7191e
F ext/fts3/fts3_aux.c 9e931f55eed8498dafe7bc1160f10cbb1a652fdf
F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d
-F ext/fts3/fts3_write.c c0af09a04021926d7d84094fa950defc9213416d
+F ext/fts3/fts3_write.c 388a7c7119f322d8fd4a5c19c9bd5793da47ccce
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
-F src/insert.c cdee360e5cea59db6c4a980e4360499631222af6
+F src/insert.c 3eea5a53d2644116fb865afaa4699fabe62b441c
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff
F src/shell.c 72e7e176bf46d5c6518d15ac4ad6847c4bb5df79
-F src/sqlite.h.in fe9a777d43276b4778e92b16a8b89ea6c38bb32b
+F src/sqlite.h.in 92f2daa48c1926d79db79229fb583cdb22d2d4c5
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
-F src/sqliteInt.h ac8f3f5846275c634f6649969304a9e97f6f9854
+F src/sqliteInt.h 5facb244a286e5c9ecd2f59758019f24a9245c8e
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
F src/trigger.c 144cc18bb701f3286484aae4292a9531f09278c8
-F src/update.c 81911be16ece3c3e7716aa18565b4814ec41f8b9
+F src/update.c 5bcb56e5c7380a2eecb0e71891dbd4ad7437748f
F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60
F src/util.c 465fe10aabf0ca7d7826a156dab919b0b65c525a
F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e
-F src/vdbe.c 05deeec6659f2579674a5e6510b3ada2a442f8d5
+F src/vdbe.c ac7aab1148964422b0a91ae5d50d31724fbd82ec
F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797
F src/vdbeInt.h fe8f58d305e629fff02f61f655aca1d299f1f6ae
F src/vdbeapi.c e0e2672e0a96ae3f8575c8ecd02912a3e8a554a1
F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
-F src/vtab.c b0abc931f95af94c9ffdf9f747eb191cda953123
+F src/vtab.c 0e89db3e7416ccdab5138883d69ed8006a7e992c
F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794
F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
F test/fts3ao.test b83f99f70e9eec85f27d75801a974b3f820e01f9
-F test/fts3atoken.test bbb9e63a915f3df0e35d06e0add932b5bf2d54a9
-F test/fts3aux1.test 719c35cbbcc04dde8e5a54a6f69851a0af9ed1f2
+F test/fts3atoken.test 402ef2f7c2fb4b3d4fa0587df6441c1447e799b3
+F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
+F test/fts3conf.test 2dc3bce3fe20d1e9b0ecd27d4040d07a2b79d16b
F test/fts3corrupt.test 7890cc202406858386ddf390a879dcf80bc10abf
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 0ab24b133e332ad7f4517b8e113e9c241ee9af9f
-R 40e74cf200b39d155b455f390ce862eb
-U drh
-Z 87bc3e585b95e6d3397bca153c02ab82
+P ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301
+R ca5f1cf4bf0f7df53478a4e115a67980
+T *branch * vtab-conflict
+T *sym-vtab-conflict *
+T -sym-trunk *
+U dan
+Z dd80c4f8ae24b83ff1c8f809d0d54000
-ddeea5ab5f6c0c4a86cdfbbb9f24d9d54bf8d301
\ No newline at end of file
+6d2633a6d0a9bb88fb1a6adac0827dc51df2d4d2
\ No newline at end of file
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
+ sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
sqlite3MayAbort(pParse);
}else
#endif
#define SQLITE_CHECKPOINT_FULL 1
#define SQLITE_CHECKPOINT_RESTART 2
+/*
+** CAPI3REF: Virtual Table Interface Configuration
+*/
+int sqlite3_vtab_config(sqlite3*, int op, ...);
+
+/*
+** CAPI3REF: Determine The Virtual Table Conflict Policy
+*/
+#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
+int sqlite3_vtab_on_conflict(sqlite3 *);
+
+/*
+** CAPI3REF: Virtual Table Conflict Policies
+*/
+#define SQLITE_ROLLBACK 1
+/* #define SQLITE_IGNORE 2 */
+#define SQLITE_FAIL 3
+/* #define SQLITE_ABORT 4 */
+#define SQLITE_REPLACE 5
+
/*
** Undo the hack that converts floating point types to integer for
typedef struct TriggerStep TriggerStep;
typedef struct UnpackedRecord UnpackedRecord;
typedef struct VTable VTable;
+typedef struct VtabCtx VtabCtx;
typedef struct Walker Walker;
typedef struct WherePlan WherePlan;
typedef struct WhereInfo WhereInfo;
u8 dfltLockMode; /* Default locking-mode for attached dbs */
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
u8 suppressErr; /* Do not issue error messages if true */
+ u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */
int nextPagesize; /* Pagesize after VACUUM if >0 */
int nTable; /* Number of tables in the database */
CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
Hash aModule; /* populated by sqlite3_create_module() */
+#if 0
Table *pVTab; /* vtab with active Connect/Create method */
+#endif
+ VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
VTable **aVTrans; /* Virtual tables with open transactions */
int nVTrans; /* Allocated size of aVTrans */
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
Module *pMod; /* Pointer to module implementation */
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
+ u8 bConstraint; /* True if constraints are supported */
VTable *pNext; /* Next in linked list (see above) */
};
ExprList *pChanges, /* The columns to change in the UPDATE statement */
Expr *pRowidExpr, /* Expression used to recompute the rowid */
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
- Expr *pWhere /* WHERE clause of the UPDATE statement */
+ Expr *pWhere, /* WHERE clause of the UPDATE statement */
+ int onError /* ON CONFLICT strategy */
);
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/* Virtual tables must be handled separately */
if( IsVirtual(pTab) ){
updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
- pWhere);
+ pWhere, onError);
pWhere = 0;
pTabList = 0;
goto update_cleanup;
ExprList *pChanges, /* The columns to change in the UPDATE statement */
Expr *pRowid, /* Expression used to recompute the rowid */
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
- Expr *pWhere /* WHERE clause of the UPDATE statement */
+ Expr *pWhere, /* WHERE clause of the UPDATE statement */
+ int onError /* ON CONFLICT strategy */
){
Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */
ExprList *pEList = 0; /* The result set of the SELECT statement */
}
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB);
+ sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
sqlite3MayAbort(pParse);
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1);
sqlite3VdbeJumpHere(v, addr);
Mem **apArg;
Mem *pX;
+ assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback
+ || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
+ );
pVtab = pOp->p4.pVtab->pVtab;
pModule = (sqlite3_module *)pVtab->pModule;
nArg = pOp->p2;
assert( pOp->p4type==P4_VTAB );
if( ALWAYS(pModule->xUpdate) ){
+ u8 vtabOnConflict = db->vtabOnConflict;
apArg = p->apArg;
pX = &aMem[pOp->p3];
for(i=0; i<nArg; i++){
apArg[i] = pX;
pX++;
}
+ db->vtabOnConflict = pOp->p5;
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
+ db->vtabOnConflict = vtabOnConflict;
importVtabErrMsg(p, pVtab);
if( rc==SQLITE_OK && pOp->p1 ){
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
db->lastRowid = rowid;
}
- p->nChange++;
+ if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
+ if( pOp->p5==OE_Ignore ){
+ rc = SQLITE_OK;
+ }else{
+ p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5);
+ }
+ }else{
+ p->nChange++;
+ }
}
break;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
+/*
+** Before a virtual table xCreate() or xConnect() method is invoked, the
+** sqlite3.pVtabCtx member variable is set to point to an instance of
+** this struct allocated on the stack. It is used by the implementation of
+** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which
+** are invoked only from within xCreate and xConnect methods.
+*/
+struct VtabCtx {
+ Table *pTab;
+ VTable *pVTable;
+};
+
/*
** The actual function that does the work of creating a new module.
** This function implements the sqlite3_create_module() and
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
char **pzErr
){
+ VtabCtx sCtx;
VTable *pVTable;
int rc;
const char *const*azArg = (const char *const*)pTab->azModuleArg;
pVTable->db = db;
pVTable->pMod = pMod;
- assert( !db->pVTab );
- assert( xConstruct );
- db->pVTab = pTab;
-
/* Invoke the virtual table constructor */
+ assert( &db->pVtabCtx );
+ assert( xConstruct );
+ sCtx.pTab = pTab;
+ sCtx.pVTable = pVTable;
+ db->pVtabCtx = &sCtx;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
+ db->pVtabCtx = 0;
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
if( SQLITE_OK!=rc ){
** the sqlite3_vtab object if successful. */
pVTable->pVtab->pModule = pMod->pModule;
pVTable->nRef = 1;
- if( db->pVTab ){
+ if( sCtx.pTab ){
const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
sqlite3VtabUnlock(pVTable);
}
sqlite3DbFree(db, zModuleName);
- db->pVTab = 0;
return rc;
}
char *zErr = 0;
sqlite3_mutex_enter(db->mutex);
- pTab = db->pVTab;
+ pTab = db->pVtabCtx->pTab;
if( !pTab ){
sqlite3Error(db, SQLITE_MISUSE, 0);
sqlite3_mutex_leave(db->mutex);
pParse->pNewTable->nCol = 0;
pParse->pNewTable->aCol = 0;
}
- db->pVTab = 0;
+ db->pVtabCtx->pTab = 0;
}else{
sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
}
}
+int sqlite3_vtab_on_conflict(sqlite3 *db){
+ int aMap[] = {
+ SQLITE_ROLLBACK, SQLITE_IGNORE, SQLITE_ABORT, SQLITE_FAIL, SQLITE_REPLACE
+ };
+ assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 );
+ assert( OE_Ignore==4 && OE_Replace==5 );
+ assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 );
+ return aMap[db->vtabOnConflict-1];
+}
+
+
+int sqlite3_vtab_config(sqlite3 *db, int op, ...){
+ va_list ap;
+ int rc = SQLITE_OK;
+
+ sqlite3_mutex_enter(db->mutex);
+
+ va_start(ap, op);
+ switch( op ){
+ case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
+ VtabCtx *p = db->pVtabCtx;
+ if( !p ){
+ rc = SQLITE_MISUSE_BKPT;
+ }else{
+ assert( (p->pTab->tabFlags & TF_Virtual)!=0 );
+ p->pVTable->bConstraint = (u8)va_arg(ap, int);
+ }
+ break;
+ }
+ default:
+ rc = SQLITE_MISUSE_BKPT;
+ break;
+ }
+ va_end(ap);
+
+ if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
#endif /* SQLITE_OMIT_VIRTUALTABLE */
do_icu_test fts3token-4.6 MiddleOfTheOcean $input $output
do_icu_test fts3token-4.7 th_TH $input $output
do_icu_test fts3token-4.8 en_US $input $output
-}
-do_execsql_test 5.1 {
- CREATE VIRTUAL TABLE x1 USING fts3(name,TOKENIZE icu en_US);
- insert into x1 (name) values (NULL);
- insert into x1 (name) values (NULL);
- delete from x1;
+ do_execsql_test 5.1 {
+ CREATE VIRTUAL TABLE x1 USING fts3(name,TOKENIZE icu en_US);
+ insert into x1 (name) values (NULL);
+ insert into x1 (name) values (NULL);
+ delete from x1;
+ }
}
+
do_test fts3token-internal {
execsql { SELECT fts3_tokenizer_internal_test() }
} {ok}
six 1 1 three 4 6 two 1 1
}
-do_execsql_test 1.3 {
- DELETE FROM t1;
+do_execsql_test 1.3.1 { DELETE FROM t1; }
+do_execsql_test 1.3.2 {
SELECT term, documents, occurrences FROM terms WHERE col = '*';
-} {}
+}
do_execsql_test 1.4 {
INSERT INTO t1 VALUES('a b a b a b a');
--- /dev/null
+# 2011 April 25
+#
+# 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.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this script is testing the FTS3 module.
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix fts3conf
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+ finish_test
+ return
+}
+
+do_execsql_test 1.0 {
+ 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"
+
+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}
+}] {
+ 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]
+}
+
+finish_test