/ Check-in [abdd70ae]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add documentation for the newly introduced sqlite3_vtab_config() and on_conflict() API functions. Test that encountering an SQLITE_MISMATCH in fts3 does not corrupt the full text index.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | vtab-conflict
Files: files | file ages | folders
SHA1: abdd70ae0424ccadb7edaf16e970c78b5257d23c
User & Date: dan 2011-04-27 16:02:46
Context
2011-04-28
18:46
Have r-tree virtual tables support on-conflict clauses. check-in: 822ab52f user: dan tags: vtab-conflict
2011-04-27
16:02
Add documentation for the newly introduced sqlite3_vtab_config() and on_conflict() API functions. Test that encountering an SQLITE_MISMATCH in fts3 does not corrupt the full text index. check-in: abdd70ae user: dan tags: vtab-conflict
12:08
Fix problems related to savepoint rollback and fts3. check-in: ff69f823 user: dan tags: vtab-conflict
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3_write.c.

2730
2731
2732
2733
2734
2735
2736
2737


2738
2739
2740
2741
2742
2743
2744
      ** 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;
      }







|
>
>







2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
      ** 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 fts3DeleteByRowid is 
      ** invoked, it will delete zero rows (since no row will have
      ** docid=$pNewRowid if $pNewRowid is not an integer value).
      */
      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 src/sqlite.h.in.

6385
6386
6387
6388
6389
6390
6391



6392
6393
6394
6395
6396
6397
6398






































6399

6400
6401
6402
6403
6404
6405
6406
6407

6408
6409
6410
6411
6412
6413
6414
6415


6416
6417
6418
6419
6420
6421
6422
/*
** CAPI3REF: Checkpoint operation parameters
**
** These constants can be used as the 3rd parameter to
** [sqlite3_wal_checkpoint_v2()].  See the [sqlite3_wal_checkpoint_v2()]
** documentation for additional information about the meaning and use of
** each of these values.



*/
#define SQLITE_CHECKPOINT_PASSIVE 0
#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
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT







>
>
>







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>




|
|
|
<
>
|
|






>
>







6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448

6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
/*
** CAPI3REF: Checkpoint operation parameters
**
** These constants can be used as the 3rd parameter to
** [sqlite3_wal_checkpoint_v2()].  See the [sqlite3_wal_checkpoint_v2()]
** documentation for additional information about the meaning and use of
** each of these values.
**
** <dt>SQLITE_CONFIG_GETMUTEX</dt>
** <dd> ^(This option takes a single argument which is a pointer to an
*/
#define SQLITE_CHECKPOINT_PASSIVE 0
#define SQLITE_CHECKPOINT_FULL    1
#define SQLITE_CHECKPOINT_RESTART 2

/*
** CAPI3REF: Virtual Table Interface Configuration
**
** This function is called by a virtual table implementation to configure
** various facets of the virtual table interface. At present, there is only
** one option that may be configured using this function. Further options
** may be added in the future.
**
** <dl>
**   <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT
**   <dd>If the second argument to sqlite3_vtab_config() is
**       SQLITE_VTAB_CONSTRAINT_SUPPORT, then SQLite expects this function to
**       have been called with three arguments, the third of which being of
**       type 'int'. If the third argument is zero, then the virtual table
**       is indicating that it does not support constraints. In this case if
**       a call to the xUpdate method returns SQLITE_CONSTRAINT, the entire
**       statement is rolled back as if [ON CONFLICT | OR ABORT] had been
**       specified as part of the users SQL statement, regardless of the actual
**       ON CONFLICT mode specified.
**
**       If the third argument passed is non-zero, then the virtual table
**       implementation must guarantee that if xUpdate returns 
**       SQLITE_CONSTRAINT, it does so before any modifications to internal
**       or persistent data structures have been made. If the [ON CONFLICT]
**       mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite is able to roll back
**       a statement or database transaction, and abandon or continue processing
**       the current SQL statement as appropriate. If the ON CONFLICT mode is
**       REPLACE and the xUpdate method returns SQLITE_CONSTRAINT, SQLite
**       handles this as if the ON CONFLICT mode had been ABORT.
**
**       Virtual table implementations that are required to handle OR REPLACE
**       must do so within the xUpdate method. If a call to the 
**       [sqlite3_vtab_on_conflict()] function indicates that the current ON 
**       CONFLICT policy is REPLACE, the virtual table implementation should 
**       silently replace the appropriate rows within the xUpdate callback and
**       return SQLITE_OK. Or, if this is not possible, it may return
**       SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT 
**       constraint handling.
** </dl>
** 
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
int sqlite3_vtab_config(sqlite3*, int op, ...);

/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
**
** This function may only be called from within a call to the xUpdate method
** of a virtual table implementation for an INSERT or UPDATE operation. The

** value returned is one of SQLITE_ROLLBACK, SQLITE_IGNORE, SQLITE_FAIL,
** SQLITE_ABORT or SQLITE_REPLACE, according to the [ON CONFLICT] mode of the 
** SQL statement that triggered the callback.
*/
#define SQLITE_ROLLBACK 1
/* #define SQLITE_IGNORE 2 */
#define SQLITE_FAIL     3
/* #define SQLITE_ABORT 4 */
#define SQLITE_REPLACE  5
int sqlite3_vtab_on_conflict(sqlite3 *);



/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT

Changes to test/fts3conf.test.

52
53
54
55
56
57
58



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
131
132
133
134
135
136
137










138
139
    DROP TABLE temp.fts3check2;
    DROP TABLE temp.fts3check3;
  }
  
  uplevel [list do_test $tn [list set {} $m1] $m2]
}




proc sql_uses_stmt {db sql} {
  set stmt [sqlite3_prepare db $sql -1 dummy]
  set uses [uses_stmt_journal $stmt]
  sqlite3_finalize $stmt
  return $uses
}




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);
................................................................................
    SAVEPOINT a;
      INSERT INTO t1 VALUES('x y z');
    ROLLBACK TO a;
  COMMIT;
}
fts3_integrity 2.1.2 db t1












finish_test







>
>
>






<
<
<







 







>
>
>
>
>
>
>
>
>
>


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67



68
69
70
71
72
73
74
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
    DROP TABLE temp.fts3check2;
    DROP TABLE temp.fts3check3;
  }
  
  uplevel [list do_test $tn [list set {} $m1] $m2]
}

# Return true if the SQL statement passed as the second argument uses a
# statement transaction.
#
proc sql_uses_stmt {db sql} {
  set stmt [sqlite3_prepare db $sql -1 dummy]
  set uses [uses_stmt_journal $stmt]
  sqlite3_finalize $stmt
  return $uses
}




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);
................................................................................
    SAVEPOINT a;
      INSERT INTO t1 VALUES('x y z');
    ROLLBACK TO a;
  COMMIT;
}
fts3_integrity 2.1.2 db t1

do_catchsql_test 2.2.1 {
  DELETE FROM t1;
  BEGIN;
    INSERT INTO t1(docid, x) VALUES(0, 'a b c');
    INSERT INTO t1(docid, x) VALUES(1, 'a b c');
    REPLACE INTO t1(docid, x) VALUES('zero', 'd e f');
} {1 {datatype mismatch}}
do_execsql_test 2.2.2 { COMMIT }
do_execsql_test 2.2.3 { SELECT * FROM t1 } {{a b c} {a b c}}
fts3_integrity 2.2.4 db t1

finish_test