1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Five-algorithm conflict resolution appears to be working. (CVS 363)

FossilOrigin-Name: 0115518f8e4591123582e3d2bb67282111ebcf60
This commit is contained in:
drh
2002-02-03 00:56:09 +00:00
parent 663fc63a77
commit 0d65dc0e90
10 changed files with 678 additions and 567 deletions

View File

@@ -1,5 +1,5 @@
C Get\sthe\sABORT\sconflict\sresolution\salgorithm\sworking.\s(CVS\s362)
D 2002-02-02T18:49:20
C Five-algorithm\sconflict\sresolution\sappears\sto\sbe\sworking.\s(CVS\s363)
D 2002-02-03T00:56:10
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -19,21 +19,21 @@ F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1
F publish.sh 5b59f4aff037aafa0e4a3b6fa599495dbd73f360
F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 94deba286af8e1f665d98378c099da2f7455f291
F src/btree.c ba5712cf620f80055948cc41157e14eab6ceee86
F src/btree.h a94bef69f5174461331b6b9ae45a2d84f05af6db
F src/build.c 397d78ce466e3c22d56de85ae23d8a2777d3b9e6
F src/build.c 0c7346d0522e59be67a4bb841020540d8ba5d136
F src/delete.c f8ad71be53cf18656b6573de65395852fe817f0c
F src/expr.c a2a87dbd411a508ff89dffa90505ad42dac2f920
F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46
F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
F src/insert.c 051e909cf4c8505aae930dcd773215404e187f23
F src/insert.c 173da7b06fe9282e0f529ff1e599460304ceeb23
F src/main.c 300320ba68d3e5b22c2c5b2c07fa884878202181
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
F src/os.c 1953080d14098cd45e5bde88941567688efb72b1
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
F src/pager.c 4059bda97a7e10083b77b7d347fea45426b08589
F src/pager.h b28f004e2f5541dc60cc32db01bf80cf4d056283
F src/parse.y 88856227ae8472d0f4ae8514bc9561a6ca060690
F src/parse.y f081d7d4ef17deb2e20511addd32d07e277edc25
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
F src/random.c f6b36bec5ebd3edb3440224bf5bf811fe4ac9a1b
F src/select.c fc11d5a8c2bae1b62d8028ffb111c773ad6bf161
@@ -49,7 +49,7 @@ F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b
F src/tokenize.c 01a09db6adf933e941db1b781789a0c175be6504
F src/update.c 95459f94a061860bf8e5716b3426a5ba85c79103
F src/util.c 8f8973dd55a6ec63be9632fc5de86965c99d6327
F src/vdbe.c 3e9d9dba06fb7f6fe85ca3c345eedd32bf27f3a7
F src/vdbe.c df1c920e74b2cd76d763833a655fbabb67f17237
F src/vdbe.h 3791edabb212038ae5fbcfa72580204596be01a7
F src/where.c 2dda39367f193194e4c7d2e0dcab31527d9d8aba
F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
@@ -57,7 +57,7 @@ F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F test/btree.test 6ab4dc5f595905a276ef588fad3c9236dc07a47b
F test/btree2.test 08e9485619265cbaf5d11bd71f357cdc26bb87e0
F test/btree3.test 9caa9e22491dd8cd8aa36d7ac3b48b089817c895
F test/conflict.test 70d40d77bb83f326574488d3cde1d0f3c51a0949
F test/conflict.test dd1b380595bb48b90289d761f4d11a46d7c60178
F test/copy.test 9ff0063c0b95b3d51b8d0c7fe0ff51dabaa66549
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
F test/expr.test c8a495050dcec3f9e68538c3ef466726933302c1
@@ -108,21 +108,21 @@ F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
F www/c_interface.tcl 82a026b1681757f13b3f62e035f3a31407c1d353
F www/changes.tcl 5c3b5b80d7144d46f100f333d4cab6184828a6c2
F www/conflict.tcl 3f70c01680b8d763bf3305eb67f6d85fdf83b497
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/faq.tcl 32cbc134879871604070d4cc3a32e73fb22a35f9
F www/formatchng.tcl 2d9a35c787823b48d72a5c64bb5414a43e26d5ad
F www/index.tcl 748614d8208c761ed3840e7958b8eed04de81822
F www/lang.tcl 7ad595247fd81f394012a0cfd84ccd6241b9e59a
F www/lang.tcl 260f3f9015344634ed9c2518f9a856462d37d6a6
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P aaa53e113ef849e34883ead8ae584c722ad967db
R f2763ccecef4a6c8cd264dd83b3c6a22
P 9be4d4c6f12056782966396dca0b8e2d384d0cf2
R 60fe69f0169f5844176ca5b7853e2e65
U drh
Z fb37183391242f0b96b036b1bf3ee1ea
Z fa5a72d3a4d7961b510d6a8d5ba99c2c

View File

@@ -1 +1 @@
9be4d4c6f12056782966396dca0b8e2d384d0cf2
0115518f8e4591123582e3d2bb67282111ebcf60

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.47 2002/02/02 18:49:20 drh Exp $
** $Id: btree.c,v 1.48 2002/02/03 00:56:10 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -816,7 +816,9 @@ int sqliteBtreeRollback(Btree *pBt){
*/
int sqliteBtreeBeginCkpt(Btree *pBt){
int rc;
if( !pBt->inTrans || pBt->inCkpt ) return SQLITE_ERROR;
if( !pBt->inTrans || pBt->inCkpt ){
return SQLITE_ERROR;
}
rc = sqlitepager_ckpt_begin(pBt->pPager);
pBt->inCkpt = 1;
return rc;
@@ -834,6 +836,7 @@ int sqliteBtreeCommitCkpt(Btree *pBt){
}else{
rc = SQLITE_OK;
}
pBt->inCkpt = 0;
return rc;
}
@@ -856,6 +859,7 @@ int sqliteBtreeRollbackCkpt(Btree *pBt){
}
}
rc = sqlitepager_ckpt_rollback(pBt->pPager);
pBt->inCkpt = 0;
return rc;
}

View File

@@ -25,7 +25,7 @@
** ROLLBACK
** PRAGMA
**
** $Id: build.c,v 1.71 2002/02/02 18:49:20 drh Exp $
** $Id: build.c,v 1.72 2002/02/03 00:56:10 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -518,7 +518,6 @@ void sqliteAddNotNull(Parse *pParse, int onError){
int i;
if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1;
if( onError==OE_Default ) onError = OE_Abort;
if( i>=0 ) p->aCol[i].notNull = onError;
}
@@ -618,7 +617,6 @@ void sqliteAddPrimaryKey(Parse *pParse, IdList *pList, int onError){
if( iCol>=0 && iCol<pTab->nCol ){
zType = pTab->aCol[iCol].zType;
}
if( onError==OE_Default ) onError = OE_Abort;
if( pParse->db->file_format>=1 &&
zType && sqliteStrICmp(zType, "INTEGER")==0 ){
pTab->iPKey = iCol;
@@ -854,7 +852,6 @@ void sqliteCreateIndex(
int hideName = 0; /* Do not put table name in the hash table */
if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
if( onError==OE_Default ) onError = OE_Abort;
/*
** Find the table that is to be indexed. Return early if not found.

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.40 2002/02/02 18:49:20 drh Exp $
** $Id: insert.c,v 1.41 2002/02/03 00:56:10 drh Exp $
*/
#include "sqliteInt.h"
@@ -396,9 +396,6 @@ void sqliteGenerateConstraintChecks(
v = sqliteGetVdbe(pParse);
assert( v!=0 );
nCol = pTab->nCol;
if( overrideError==OE_Default ){
overrideError = pParse->db->onError;
}
/* Test all NOT NULL constraints.
*/
@@ -412,7 +409,8 @@ void sqliteGenerateConstraintChecks(
if( overrideError!=OE_Default ){
onError = overrideError;
}else if( onError==OE_Default ){
onError = OE_Abort;
onError = pParse->db->onError;
if( onError==OE_Default ) onError = OE_Abort;
}
if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){
onError = OE_Abort;
@@ -447,16 +445,17 @@ void sqliteGenerateConstraintChecks(
/* Test all UNIQUE constraints. Add index records as we go.
*/
if( (recnoChng || !isUpdate) && pTab->iPKey>=0 && pTab->keyConf!=OE_Replace
&& overrideError!=OE_Replace ){
sqliteVdbeAddOp(v, OP_Dup, nCol, 1);
jumpInst = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
if( (recnoChng || !isUpdate) && pTab->iPKey>=0 ){
onError = pTab->keyConf;
if( overrideError!=OE_Default ){
onError = overrideError;
}else if( onError==OE_Default ){
onError = OE_Abort;
onError = pParse->db->onError;
if( onError==OE_Default ) onError = OE_Abort;
}
if( onError!=OE_Replace ){
sqliteVdbeAddOp(v, OP_Dup, nCol, 1);
jumpInst = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
switch( onError ){
case OE_Rollback:
case OE_Abort:
@@ -478,6 +477,7 @@ void sqliteGenerateConstraintChecks(
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
}
}
}
extra = 0;
for(extra=(-1), iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
if( aIdxUsed && aIdxUsed[iCur]==0 ) continue;
@@ -497,7 +497,8 @@ void sqliteGenerateConstraintChecks(
if( overrideError!=OE_Default ){
onError = overrideError;
}else if( onError==OE_Default ){
onError = OE_Abort;
onError = pParse->db->onError;
if( onError==OE_Default ) onError = OE_Abort;
}
sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1);
jumpInst = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);

View File

@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.46 2002/02/02 15:01:16 drh Exp $
** @(#) $Id: parse.y,v 1.47 2002/02/03 00:56:10 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -57,10 +57,7 @@ explain ::= EXPLAIN. {pParse->explain = 1;}
///////////////////// Begin and end transactions. ////////////////////////////
//
// For now, disable the ability to change the default conflict resolution
// algorithm in a transaction. We made add it back later.
// cmd ::= BEGIN trans_opt onconf(R). {sqliteBeginTransaction(pParse,R);}
cmd ::= BEGIN trans_opt. {sqliteBeginTransaction(pParse, OE_Default);}
cmd ::= BEGIN trans_opt onconf(R). {sqliteBeginTransaction(pParse,R);}
trans_opt ::= .
trans_opt ::= TRANSACTION.
trans_opt ::= TRANSACTION ids.

View File

@@ -30,7 +30,7 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.114 2002/02/02 18:49:21 drh Exp $
** $Id: vdbe.c,v 1.115 2002/02/03 00:56:10 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -4511,10 +4511,9 @@ cleanup:
break;
}
}
}else{
}
sqliteBtreeCommitCkpt(pBt);
if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
}
return rc;
/* Jump to here if a malloc() fails. It's hard to get a malloc()

View File

@@ -13,263 +13,368 @@
# This file implements tests for the conflict resolution extension
# to SQLite.
#
# $Id: conflict.test,v 1.4 2002/01/31 15:54:23 drh Exp $
# $Id: conflict.test,v 1.5 2002/02/03 00:56:11 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a table with three fields, two of which must be
# UNIQUE.
# Create tables for the first group of tests.
#
do_test conflict-1.1 {
do_test conflict-1.0 {
execsql {
CREATE TABLE t1(a, b, c, UNIQUE(a,b));
INSERT INTO t1 VALUES(1,2,3);
CREATE TABLE t2(x);
SELECT c FROM t1 ORDER BY c;
}
} {3}
do_test conflict-1.2 {
catchsql {
INSERT INTO t1 VALUES(1,2,4);
SELECT c FROM t1 ORDER BY c;
}
} {1 {constraint failed}}
do_test conflict-1.3 {
catchsql {
INSERT OR IGNORE INTO t1 VALUES(1,2,4);
SELECT c FROM t1 ORDER BY c;
}
} {0 3}
do_test conflict-1.4 {
catchsql {
INSERT OR REPLACE INTO t1 VALUES(1,2,4);
SELECT c FROM t1 ORDER BY c;
}
} {0 4}
do_test conflict-1.5 {
catchsql {
INSERT OR ABORT INTO t1 VALUES(1,2,5);
SELECT c FROM t1 ORDER BY c;
}
} {1 {constraint failed}}
do_test conflict-1.6 {
catchsql {
INSERT OR IGNORE INTO t1 VALUES(1,2,5);
SELECT c FROM t1 ORDER BY c;
}
} {0 4}
do_test conflict-1.7 {
catchsql {
INSERT OR REPLACE INTO t1 VALUES(1,2,5);
SELECT c FROM t1 ORDER BY c;
}
} {0 5}
do_test conflict-1.8 {
catchsql {
INSERT OR ABORT INTO t1 VALUES(1,2,6);
SELECT c FROM t1 ORDER BY c;
}
} {1 {constraint failed}}
} {}
do_test conflict-1.9 {
execsql {
BEGIN;
CREATE TABLE t2(a,b,c);
INSERT INTO t2 VALUES(1,2,11);
INSERT INTO t2 VALUES(1,2,12);
INSERT INTO t2 VALUES(1,2,13);
INSERT INTO t2 VALUES(1,2,14);
INSERT INTO t2 VALUES(1,3,21);
INSERT INTO t2 VALUES(1,3,22);
INSERT INTO t2 VALUES(1,3,23);
INSERT INTO t2 VALUES(1,3,24);
COMMIT;
SELECT count(*) FROM t2;
}
} 8
do_test conflict-1.10 {
catchsql {
INSERT OR IGNORE INTO t1 SELECT a,b,c FROM t2 ORDER BY c;
SELECT c FROM t1 ORDER BY c;
}
} {0 {5 21}}
do_test conflict-1.11 {
catchsql {
INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c;
SELECT c FROM t1 ORDER BY c;
}
} {0 {14 24}}
###### Fix me!
do_test conflict-1.12 {
catchsql {
INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c DESC;
SELECT c FROM t1 ORDER BY c;
}
} {0 {14 24}}
do_test conflict-1.13 {
execsql {
BEGIN;
# Six columns of configuration data as follows:
#
# i The reference number of the test
# conf The conflict resolution algorithm on the BEGIN statement
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
#
foreach {i conf cmd t0 t1 t2} {
1 {} INSERT 1 {} 1
2 {} {INSERT OR IGNORE} 0 3 1
3 {} {INSERT OR REPLACE} 0 4 1
4 {} REPLACE 0 4 1
5 {} {INSERT OR FAIL} 1 {} 1
6 {} {INSERT OR ABORT} 1 {} 1
7 {} {INSERT OR ROLLBACK} 1 {} {}
8 IGNORE INSERT 0 3 1
9 IGNORE {INSERT OR IGNORE} 0 3 1
10 IGNORE {INSERT OR REPLACE} 0 4 1
11 IGNORE REPLACE 0 4 1
12 IGNORE {INSERT OR FAIL} 1 {} 1
13 IGNORE {INSERT OR ABORT} 1 {} 1
14 IGNORE {INSERT OR ROLLBACK} 1 {} {}
15 REPLACE INSERT 0 4 1
16 FAIL INSERT 1 {} 1
17 ABORT INSERT 1 {} 1
18 ROLLBACK INSERT 1 {} {}
} {
do_test conflict-1.$i {
if {$conf!=""} {set conf "ON CONFLICT $conf"}
set r0 [catch {execsql [subst {
DELETE FROM t1;
DELETE FROM t2;
INSERT INTO t1 VALUES(1,2,3);
INSERT INTO t1 VALUES(1,3,4);
INSERT INTO t1 VALUES(2,3,5);
COMMIT;
SELECT * FROM t1 ORDER BY c;
}
} {1 2 3 1 3 4 2 3 5}
do_test conflict-1.14 {
catchsql {
UPDATE OR ABORT t1 SET b=3 WHERE b=2;
SELECT c FROM t1 ORDER BY c;
}
} {1 {constraint failed}};
do_test conflict-1.15 {
catchsql {
UPDATE t1 SET b=3 WHERE b=2;
SELECT c FROM t1 ORDER BY c;
}
} {1 {constraint failed}};
do_test conflict-1.16 {
catchsql {
UPDATE OR IGNORE t1 SET b=3 WHERE b=2;
SELECT * FROM t1 ORDER BY c;
}
} {0 {1 2 3 1 3 4 2 3 5}}
do_test conflict-1.17 {
catchsql {
UPDATE OR REPLACE t1 SET b=3 WHERE b=2;
SELECT * FROM t1 ORDER BY c;
}
} {0 {1 3 3 2 3 5}}
BEGIN $conf;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,4);
}]} r1]
execsql {COMMIT}
if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
do_test conflict-2.1 {
# Create tables for the first group of tests.
#
do_test conflict-2.0 {
execsql {
DROP TABLE t1;
DROP TABLE t2;
CREATE TABLE t1(a integer primary key, b, c, UNIQUE(a,b));
CREATE INDEX t1b ON t1(b);
CREATE INDEX t1bc ON t1(b,c);
INSERT INTO t1 VALUES(1,2,3);
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(a,b));
CREATE TABLE t2(x);
SELECT c FROM t1 ORDER BY c;
}
} {3}
do_test conflict-2.2 {
catchsql {
INSERT INTO t1 VALUES(1,2,4);
SELECT c FROM t1 ORDER BY c;
}
} {1 {constraint failed}}
do_test conflict-2.3 {
catchsql {
INSERT OR IGNORE INTO t1 VALUES(1,2,4);
SELECT c FROM t1 ORDER BY c;
}
} {0 3}
do_test conflict-2.4 {
catchsql {
INSERT OR REPLACE INTO t1 VALUES(1,2,4);
SELECT c FROM t1 ORDER BY c;
}
} {0 4}
do_test conflict-2.5 {
catchsql {
INSERT OR ABORT INTO t1 VALUES(1,2,5);
SELECT c FROM t1 ORDER BY c;
}
} {1 {constraint failed}}
do_test conflict-2.6 {
catchsql {
INSERT OR IGNORE INTO t1 VALUES(1,2,5);
SELECT c FROM t1 ORDER BY c;
}
} {0 4}
do_test conflict-2.7 {
catchsql {
INSERT OR REPLACE INTO t1 VALUES(1,2,5);
SELECT c FROM t1 ORDER BY c;
}
} {0 5}
do_test conflict-2.8 {
catchsql {
INSERT OR ABORT INTO t1 VALUES(1,2,6);
SELECT c FROM t1 ORDER BY c;
}
} {1 {constraint failed}}
} {}
do_test conflict-2.9 {
execsql {
BEGIN;
CREATE TABLE t2(a,b,c INTEGER PRIMARY KEY);
INSERT INTO t2 VALUES(1,2,11);
INSERT INTO t2 VALUES(1,2,12);
INSERT INTO t2 VALUES(1,2,13);
INSERT INTO t2 VALUES(1,2,14);
INSERT INTO t2 VALUES(2,2,21);
INSERT INTO t2 VALUES(2,2,22);
INSERT INTO t2 VALUES(2,2,23);
INSERT INTO t2 VALUES(2,2,24);
COMMIT;
SELECT count(*) FROM t2;
}
} 8
do_test conflict-2.10 {
catchsql {
INSERT OR IGNORE INTO t1 SELECT a,b,c FROM t2 ORDER BY c;
SELECT c FROM t1 ORDER BY c;
}
} {0 {5 21}}
do_test conflict-2.11 {
catchsql {
INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c;
SELECT c FROM t1 ORDER BY c;
}
} {0 {14 24}}
###### Fix me!
do_test conflict-2.12 {
catchsql {
INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c DESC;
SELECT c FROM t1 ORDER BY c;
}
} {0 {14 24}}
do_test conflict-2.13 {
execsql {
BEGIN;
# Six columns of configuration data as follows:
#
# i The reference number of the test
# conf The conflict resolution algorithm on the BEGIN statement
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
#
foreach {i conf cmd t0 t1 t2} {
1 {} INSERT 1 {} 1
2 {} {INSERT OR IGNORE} 0 3 1
3 {} {INSERT OR REPLACE} 0 4 1
4 {} REPLACE 0 4 1
5 {} {INSERT OR FAIL} 1 {} 1
6 {} {INSERT OR ABORT} 1 {} 1
7 {} {INSERT OR ROLLBACK} 1 {} {}
8 IGNORE INSERT 0 3 1
9 IGNORE {INSERT OR IGNORE} 0 3 1
10 IGNORE {INSERT OR REPLACE} 0 4 1
11 IGNORE REPLACE 0 4 1
12 IGNORE {INSERT OR FAIL} 1 {} 1
13 IGNORE {INSERT OR ABORT} 1 {} 1
14 IGNORE {INSERT OR ROLLBACK} 1 {} {}
15 REPLACE INSERT 0 4 1
16 FAIL INSERT 1 {} 1
17 ABORT INSERT 1 {} 1
18 ROLLBACK INSERT 1 {} {}
} {
do_test conflict-2.$i {
if {$conf!=""} {set conf "ON CONFLICT $conf"}
set r0 [catch {execsql [subst {
DELETE FROM t1;
DELETE FROM t2;
INSERT INTO t1 VALUES(1,2,3);
INSERT INTO t1 VALUES(2,3,4);
INSERT INTO t1 VALUES(3,3,5);
COMMIT;
SELECT * FROM t1 ORDER BY c;
}
} {1 2 3 2 3 4 3 3 5}
do_test conflict-2.14 {
catchsql {
UPDATE OR ABORT t1 SET a=2, b=3 WHERE b=2;
BEGIN $conf;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,4);
}]} r1]
execsql {COMMIT}
if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
# Create tables for the first group of tests.
#
do_test conflict-3.0 {
execsql {
DROP TABLE t1;
DROP TABLE t2;
CREATE TABLE t1(a, b, c INTEGER PRIMARY KEY, UNIQUE(a,b));
CREATE TABLE t2(x);
SELECT c FROM t1 ORDER BY c;
}
} {1 {constraint failed}};
do_test conflict-2.15 {
catchsql {
UPDATE t1 SET a=2, b=3 WHERE b=2;
SELECT c FROM t1 ORDER BY c;
} {}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# conf The conflict resolution algorithm on the BEGIN statement
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
#
foreach {i conf cmd t0 t1 t2} {
1 {} INSERT 1 {} 1
2 {} {INSERT OR IGNORE} 0 3 1
3 {} {INSERT OR REPLACE} 0 4 1
4 {} REPLACE 0 4 1
5 {} {INSERT OR FAIL} 1 {} 1
6 {} {INSERT OR ABORT} 1 {} 1
7 {} {INSERT OR ROLLBACK} 1 {} {}
8 IGNORE INSERT 0 3 1
9 IGNORE {INSERT OR IGNORE} 0 3 1
10 IGNORE {INSERT OR REPLACE} 0 4 1
11 IGNORE REPLACE 0 4 1
12 IGNORE {INSERT OR FAIL} 1 {} 1
13 IGNORE {INSERT OR ABORT} 1 {} 1
14 IGNORE {INSERT OR ROLLBACK} 1 {} {}
15 REPLACE INSERT 0 4 1
16 FAIL INSERT 1 {} 1
17 ABORT INSERT 1 {} 1
18 ROLLBACK INSERT 1 {} {}
} {
do_test conflict-3.$i {
if {$conf!=""} {set conf "ON CONFLICT $conf"}
set r0 [catch {execsql [subst {
DELETE FROM t1;
DELETE FROM t2;
INSERT INTO t1 VALUES(1,2,3);
BEGIN $conf;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,4);
}]} r1]
execsql {COMMIT}
if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
do_test conflict-4.0 {
execsql {
DROP TABLE t2;
CREATE TABLE t2(x);
SELECT x FROM t2;
}
} {1 {constraint failed}};
do_test conflict-2.16 {
catchsql {
UPDATE OR IGNORE t1 SET a=2, b=3 WHERE b=2;
SELECT * FROM t1 ORDER BY c;
} {}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# conf1 The conflict resolution algorithm on the UNIQUE constraint
# conf2 The conflict resolution algorithm on the BEGIN statement
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
#
foreach {i conf1 conf2 cmd t0 t1 t2} {
1 {} {} INSERT 1 {} 1
2 REPLACE {} INSERT 0 4 1
3 IGNORE {} INSERT 0 3 1
4 FAIL {} INSERT 1 {} 1
5 ABORT {} INSERT 1 {} 1
6 ROLLBACK {} INSERT 1 {} {}
7 REPLACE {} {INSERT OR IGNORE} 0 3 1
8 IGNORE {} {INSERT OR REPLACE} 0 4 1
9 FAIL {} {INSERT OR IGNORE} 0 3 1
10 ABORT {} {INSERT OR REPLACE} 0 4 1
11 ROLLBACK {} {INSERT OR IGNORE } 0 3 1
12 REPLACE IGNORE INSERT 0 4 1
13 IGNORE REPLACE INSERT 0 3 1
14 FAIL IGNORE INSERT 1 {} 1
15 ABORT REPLACE INSERT 1 {} 1
16 ROLLBACK IGNORE INSERT 1 {} {}
} {
do_test conflict-4.$i {
if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"}
if {$conf2!=""} {set conf2 "ON CONFLICT $conf2"}
set r0 [catch {execsql [subst {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,UNIQUE(a,b) $conf1);
DELETE FROM t2;
INSERT INTO t1 VALUES(1,2,3);
BEGIN $conf2;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,4);
}]} r1]
execsql {COMMIT}
if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
do_test conflict-5.0 {
execsql {
DROP TABLE t2;
CREATE TABLE t2(x);
SELECT x FROM t2;
}
} {0 {1 2 3 2 3 4 3 3 5}}
do_test conflict-2.17 {
catchsql {
UPDATE OR REPLACE t1 SET a=2, b=3 WHERE b=2;
SELECT * FROM t1 ORDER BY c;
} {}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# conf1 The conflict resolution algorithm on the NOT NULL constraint
# conf2 The conflict resolution algorithm on the BEGIN statement
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
#
foreach {i conf1 conf2 cmd t0 t1 t2} {
1 {} {} INSERT 1 {} 1
2 REPLACE {} INSERT 0 5 1
3 IGNORE {} INSERT 0 {} 1
4 FAIL {} INSERT 1 {} 1
5 ABORT {} INSERT 1 {} 1
6 ROLLBACK {} INSERT 1 {} {}
7 REPLACE {} {INSERT OR IGNORE} 0 {} 1
8 IGNORE {} {INSERT OR REPLACE} 0 5 1
9 FAIL {} {INSERT OR IGNORE} 0 {} 1
10 ABORT {} {INSERT OR REPLACE} 0 5 1
11 ROLLBACK {} {INSERT OR IGNORE} 0 {} 1
12 {} {} {INSERT OR IGNORE} 0 {} 1
13 {} {} {INSERT OR REPLACE} 0 5 1
14 {} {} {INSERT OR FAIL} 1 {} 1
15 {} {} {INSERT OR ABORT} 1 {} 1
16 {} {} {INSERT OR ROLLBACK} 1 {} {}
17 {} IGNORE INSERT 0 {} 1
18 {} REPLACE INSERT 0 5 1
19 {} FAIL INSERT 1 {} 1
20 {} ABORT INSERT 1 {} 1
21 {} ROLLBACK INSERT 1 {} {}
22 REPLACE FAIL INSERT 0 5 1
23 IGNORE ROLLBACK INSERT 0 {} 1
} {
if {$t0} {set t1 {constraint failed}}
do_test conflict-5.$i {
if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"}
if {$conf2!=""} {set conf2 "ON CONFLICT $conf2"}
set r0 [catch {execsql [subst {
DROP TABLE t1;
CREATE TABLE t1(a,b,c NOT NULL $conf1 DEFAULT 5);
DELETE FROM t2;
BEGIN $conf2;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,NULL);
}]} r1]
execsql {COMMIT}
if {!$r0} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
do_test conflict-6.0 {
execsql {
DROP TABLE t2;
CREATE TABLE t2(a,b,c);
INSERT INTO t2 VALUES(1,2,1);
INSERT INTO t2 VALUES(2,3,2);
INSERT INTO t2 VALUES(3,4,1);
INSERT INTO t2 VALUES(4,5,4);
SELECT c FROM t2 ORDER BY b;
CREATE TABLE t3(x);
INSERT INTO t3 VALUES(1);
}
} {0 {2 3 3 3 3 5}}
} {1 2 1 4}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# conf1 The conflict resolution algorithm on the UNIQUE constraint
# conf2 The conflict resolution algorithm on the BEGIN statement
# cmd An UPDATE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "b" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t3
#
foreach {i conf1 conf2 cmd t0 t1 t2} {
1 {} {} UPDATE 1 {6 7 8 9} 1
2 REPLACE {} UPDATE 0 {7 6 9} 1
3 IGNORE {} UPDATE 0 {6 7 3 9} 1
4 FAIL {} UPDATE 1 {6 7 3 4} 1
5 ABORT {} UPDATE 1 {1 2 3 4} 1
6 ROLLBACK {} UPDATE 1 {1 2 3 4} 0
7 REPLACE {} {UPDATE OR IGNORE} 0 {6 7 3 9} 1
8 IGNORE {} {UPDATE OR REPLACE} 0 {7 6 9} 1
9 FAIL {} {UPDATE OR IGNORE} 0 {6 7 3 9} 1
10 ABORT {} {UPDATE OR REPLACE} 0 {7 6 9} 1
11 ROLLBACK {} {UPDATE OR IGNORE} 0 {6 7 3 9} 1
12 {} {} {UPDATE OR IGNORE} 0 {6 7 3 9} 1
13 {} {} {UPDATE OR REPLACE} 0 {7 6 9} 1
14 {} {} {UPDATE OR FAIL} 1 {6 7 3 4} 1
15 {} {} {UPDATE OR ABORT} 1 {1 2 3 4} 1
16 {} {} {UPDATE OR ROLLBACK} 1 {1 2 3 4} 0
17 {} IGNORE UPDATE 0 {6 7 3 9} 1
18 {} REPLACE UPDATE 0 {7 6 9} 1
19 {} FAIL UPDATE 1 {6 7 3 4} 1
20 {} ABORT UPDATE 1 {1 2 3 4} 1
21 {} ROLLBACK UPDATE 1 {1 2 3 4} 0
22 REPLACE FAIL UPDATE 0 {7 6 9} 1
23 IGNORE ROLLBACK UPDATE 0 {6 7 3 9} 1
} {
if {$t0} {set t1 {constraint failed}}
do_test conflict-6.$i {
if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"}
if {$conf2!=""} {set conf2 "ON CONFLICT $conf2"}
set r0 [catch {execsql [subst {
DROP TABLE t1;
CREATE TABLE t1(a,b,c, UNIQUE(a) $conf1);
INSERT INTO t1 SELECT * FROM t2;
UPDATE t3 SET x=0;
BEGIN $conf2;
$cmd t3 SET x=1;
$cmd t1 SET a=c+5;
}]} r1]
execsql {COMMIT}
if {!$r0} {set r1 [execsql {SELECT a FROM t1 ORDER BY b}]}
set r2 [execsql {SELECT x FROM t3}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
finish_test

View File

@@ -1,7 +1,7 @@
#
# Run this Tcl script to generate the constraint.html file.
#
set rcsid {$Id: conflict.tcl,v 1.1 2002/01/30 16:17:25 drh Exp $ }
set rcsid {$Id: conflict.tcl,v 1.2 2002/02/03 00:56:11 drh Exp $ }
puts {<html>
<head>
@@ -22,7 +22,8 @@ puts {
In most SQL databases, if you have a UNIQUE constraint on
a table and you try to do an UPDATE or INSERT that violates
that constraint, the database will aborts the operation in
progress and rolls back the current transaction.
progress, back out any prior changes associated with that
one UPDATE or INSERT command, and return an error.
This is the default behavior of SQLite.
Beginning with version 2.3.0, though, SQLite allows you to
define alternative ways for dealing with constraint violations.
@@ -32,154 +33,71 @@ This article describes those alternatives and how to use them.
<h2>Conflict Resolution Algorithms</h2>
<p>
The default conflict resolution algorithm is to abort the
operation in progress, rollback all changes, and cancel the
current transaction. Call this algorithm "ABORT". Abort
is the standard way of dealing with a constraint error
in most SQL databases.
SQLite defines five constraint conflict resolution algorithms
as follows:
</p>
<p>
Sometimes ABORT is not the most helpful way of dealing
with constraint violations. Suppose, for example, you are
<dl>
<dt><b>ROLLBACK</b></dt>
<dd><p>When a constraint violation occurs, an immediate ROLLBACK
occurs, thus ending the current transaction, and the command aborts
with a return code of SQLITE_CONSTRAINT. If no transaction is
active (other than the implied transaction that is created on every
command) then this algorithm works the same as ABORT.</p></dd>
<dt><b>ABORT</b></dt>
<dd><p>When a constraint violation occurs, the command backs out
any prior changes it might have made and aborts with a return code
of SQLITE_CONSTRAINT. But no ROLLBACK is executed so changes
from prior commands within the same transaction
are preserved. This is the default behavior for SQLite.</p></dd>
<dt><b>FAIL</b></dt>
<dd><p>When a constraint violation occurs, the command aborts with a
return code SQLITE_CONSTRAINT. But any changes to the database that
the command made prior to encountering the constraint violation
are preserved and are not backed out. For example, if an UPDATE
statement encountered a constraint violation on the 100th row that
it attempts to update, then the first 99 row changes are preserved
by change to rows 100 and beyond never occur.</p></dd>
<dt><b>IGNORE</b></dt>
<dd><p>When a constraint violation occurs, the one row that contains
the constraint violation is not inserted or changed. But the command
continues executing normally. Other rows before and after the row that
contained the constraint violation continue to be inserted or updated
normally. No error is returned.</p></dd>
<dt><b>REPLACE</b></dt>
<dd><p>When a UNIQUE constraint violation occurs, the pre-existing row
that caused the constraint violation is removed prior to inserting
or updating the current row. Thus the insert or update always occurs.
The command continues executing normally. No error is returned.</p></dd>
</dl>
<h2>Why So Many Choices?</h2>
<p>SQLite provides multiple conflict resolution algorithms for a
couple of reasons. First, SQLite tries to be roughly compatible with as
many other SQL databases as possible, but different SQL database
engines exhibit different conflict resolution strategies. For
example, PostgreSQL always uses ROLLBACK, Oracle always uses ABORT, and
MySQL usually uses FAIL but can be instructed to use IGNORE or REPLACE.
By supporting all five alternatives, SQLite provides maximum
portability.</p>
<p>Another reason for supporing multiple algorithms is that sometimes
it is useful to use an algorithm other than the default.
Suppose, for example, you are
inserting 1000 records into a database, all within a single
transaction, but one of those records is malformed and causes
a constraint error. With the default ABORT behavior, none
of the 1000 records gets inserted. But sometimes it is
desirable to just omit the single malformed insert and
finish the other 999.
</p>
a constraint error. Under PostgreSQL or Oracle, none of the
1000 records would get inserted. In MySQL, some subset of the
records that appeared before the malformed record would be inserted
but the rest would not. Neither behavior is espeically helpful.
What you really want is to use the IGNORE algorithm to insert
all but the malformed record.</p>
<p>
SQLite defines two addition conflict resolution algorithms
called "IGNORE" and "REPLACE".
If you are trying to do multiple INSERTs or UPDATEs when a constraint
fails for a single row and the conflict behavior is IGNORE, then
that row remains uninserted or unmodified. But the overall operation
is not aborted and no rollback occurs. If a constraint
fails and the behavior is REPLACE, then SQLite tries to
delete other rows in the table in order to eliminate the
constraint problem. Again, the overall operation continues
and no rollback occurs.
</p>
<p>
The default conflict resolution algorithm is always ABORT
but you can specify an alternative algorithm using special
(non-standard) syntax on the INSERT and UPDATE commands.
You can add the clause "ON CONFLICT <algorithm>" immediately
after the "INSERT" or "UPDATE" keywords to specify the
conflict resolution algorithm to use for that one operation.
(Substitute "ABORT", "IGNORE", or "REPLACE" for <algorithm>,
of course.)
</p>
Consider this example:
<blockquote><pre>
BEGIN;
CREATE TABLE t1(
a INTEGER,
b INTEGER,
c INTEGER,
UNIQUE(a,b)
);
INSERT INTO a VALUES(1,2,3);
COMMIT;
BEGIN;
INSERT INTO a VALUES(2,3,4);
INSERT INTO a VALUES(1,2,5);
</pre></blockquote>
<p>
In the last instruction, the UNIQUE constraint fails
and the entire transaction is rolled back. The database
now contains a single entry: {1,2,3}.
</p>
<blockquote><pre>
BEGIN;
INSERT ON CONFLICT IGNORE INTO a VALUES(2,3,4);
INSERT ON CONFLICT IGNORE INTO a VALUES(1,2,5);
COMMIT;
</pre></blockquote>
<p>This time the "ON CONFLICT IGNORE" clause tells SQLite to use
IGNORE semantics when a constraint fails. The second
INSERT statement fails, but the database is
not rolled back and there is no failure. The database
now contains two rows: {1,2,3} and {2,3,4}.</p>
<blockquote><pre>
BEGIN;
INSERT ON CONFLICT REPLACE INTO a VALUES(1,2,5);
COMMIT;
</pre></blockquote>
<p>Here the "ON CONFLICT REPLACE" clause tells SQLite to use REPLACE
semantics. The {1,2,3} is deleted when the {1,2,5} row
is inserted in order to satisfy the constraint. After
the above, the database contains {1,2,5} and {2,3,4}.</p>
<h2>A Syntactic Shortcut</h2>
<p>On an INSERT, the "ON CONFLICT" keywords may be omitted for brevity.
So you can say</p>
<blockquote><pre>
INSERT IGNORE INTO a VALUES(1,2,5);
</pre></blockquote>
<p>Instead of the more wordy:</p>
<blockquote><pre>
INSERT ON CONFLICT IGNORE INTO a VALUES(1,2,5);
</pre></blockquote>
<p>Unfortunately, you cannot do this with an UPDATE.</p>
<h2>Changing The Default Conflict Resolution Algorithm</h2>
<p>You can change the default conflict resolution algorithm
on a constraint-by-constraint basis using special (non-standard)
syntax in CREATE TABLE and CREATE INDEX statements. The
same "ON CONFLICT" clause that appears in INSERT and UPDATE
statements is used but the clause is attached to the constraint
in the CREATE TABLE statement. Like this:
<blockquote><pre>
CREATE TABLE t1 (
a INTEGER,
b INTEGER,
c INTEGER,
UNIQUE(a,b) ON CONFLICT REPLACE
);
</pre></blockquote>
<p>The ON CONFLICT clause in the above table definition says that
the default conflict resolution algorithm is REPLACE instead
of ABORT. REPLACE will always be used unless you override
this by saying "INSERT IGNORE" or "INSERT ABORT".</p>
<p>The ON CONFLICT clause can also appear on a NOT NULL constraint,
a PRIMARY KEY constraint, and a CHECK constraint.
(Note, however, that CHECK constraints are not currently enforced
so the ON CONFLICT clause has no effect there.)</p>
<p>A NOT NULL constraint will normally ABORT if you try to insert
a NULL. But if you substitute the REPLACE algorithm, it tries to insert
the default value in place of the NULL. If there is no default value,
then REPLACE is the same as ABORT for NOT NULL constraints.
With the IGNORE algorithm on a NOT NULL, the INSERT or UPDATE
is suppressed if the value is NULL.</p>
<h2>Portability</h2>
<p>The ON CONFLICT syntax is not standard SQL and will not
(as far as is known) work on any other database product. Furthermore,
the syntax might change in future versions of SQLite. So use it
with appropriate discretion.</p>
}
puts {

View File

@@ -1,7 +1,7 @@
#
# Run this Tcl script to generate the sqlite.html file.
#
set rcsid {$Id: lang.tcl,v 1.20 2002/01/31 15:54:23 drh Exp $}
set rcsid {$Id: lang.tcl,v 1.21 2002/02/03 00:56:11 drh Exp $}
puts {<html>
<head>
@@ -42,6 +42,7 @@ foreach {section} [lsort -index 0 -dictionary {
{{DROP TABLE} droptable}
{{DROP INDEX} dropindex}
{INSERT insert}
{REPLACE replace}
{DELETE delete}
{UPDATE update}
{SELECT select}
@@ -61,7 +62,7 @@ the sequel.</p>
}
proc Syntax {args} {
puts {<table cellpadding="15">}
puts {<table cellpadding="10">}
foreach {rule body} $args {
puts "<tr><td align=\"right\" valign=\"top\">"
puts "<i><font color=\"#ff3434\">$rule</font></i>&nbsp;::=</td>"
@@ -105,7 +106,7 @@ proc Example {text} {
Section {BEGIN TRANSACTION} createindex
Syntax {sql-statement} {
BEGIN [TRANSACTION [<name>]]
BEGIN [TRANSACTION [<name>]] [ON CONFLICT <conflict-algorithm>]
}
Syntax {sql-statement} {
END [TRANSACTION [<name>]]
@@ -119,9 +120,7 @@ ROLLBACK [TRANSACTION [<name>]]
puts {
<p>Beginning in version 2.0, SQLite supports transactions with
rollback and atomic commit. However, only a single level of
transaction is allowed. Transactions may not be nested.
</p>
rollback and atomic commit.</p>
<p>
No changes can be made to the database except within a transaction.
@@ -132,52 +131,32 @@ are committed at the conclusion of the command.
</p>
<p>
Transactions can be started manually using the BEGIN TRANSACTION
command. Such transactions persist until a COMMIT or ROLLBACK
or until an error occurs or the database is closed. If an
error is encountered or the database is closed, the transaction
is automatically rolled back. The END TRANSACTION command is
a alias for COMMIT.
Transactions can be started manually using the BEGIN
command. Such transactions usually persist until the next
COMMIT or ROLLBACK command. But a transaction will also
ROLLBACK if the database is closed or if an error occurs
and the ROLLBACK conflict resolution algorithm is specified.
See the documention on the <a href="#conflict">ON CONFLICT</a>
clause for additional information about the ROLLBACK
conflict resolution algorithm.
</p>
}
Section {ON CONFLICT clause} conflict
Syntax {conflict-clause} {
ON CONFLICT <algorithm>
} {algorithm} {
ABORT | IGNORE | REPLACE
}
puts {
<p>The ON CONFLICT clause is not a separate SQL command. It is a
non-standard clause that can appear in many other SQL commands.
It is given its own section in this document because it is not
part of standard SQL and therefore might not be familiar.</p>
<p>The ON CONFLICT clause specifies an algorithm used to resolve
constraint conflicts. The default algorithm is ABORT. When the
ABORT algorithm is in use, any constraint violation causes the
command to abort and the current transaction to be rolled back.
This is the only behavior exhibited by most SQL engines. But
SQLite allows two alternative behaviors: IGNORE and REPLACE.
The IGNORE algorithm means that when a constraint violation occurs
on a COPY, INSERT or UPDATE, the particular row that caused the constraint
violation is not inserted or changed, but other rows effected by the
COPY, INSERT, or UPDATE are insert or changed as usual.
The command is not aborted and no rollback occurs.
If the algorithm is REPLACE, then SQLite tries to
delete preexisting rows from the table to remove the constraint
violation before inserting or changing the row.</p>
<p>For additional information, see
<a href="conflict.html">conflict.html</a>.</p>
<p>
The optional ON CONFLICT clause at the end of a BEGIN statement
can be used to changed the default conflict resolution algorithm.
The normal default is ABORT. If an alternative is specified by
the ON CONFLICT clause of a BEGIN, then that alternative is used
as the default for all commands within the transaction. The default
algorithm is overridden by ON CONFLICT clauses on individual
constraints within the CREATE TABLE or CREATE INDEX statements
and by the OR clauses on COPY, INSERT, and UPDATE commands.
</p>
}
Section COPY copy
Syntax {sql-statement} {
COPY [ <conflict-clause> ] <table-name> FROM <filename>
COPY [ OR <conflict-algorithm> ] <table-name> FROM <filename>
[ USING DELIMITERS <delim> ]
}
@@ -219,7 +198,7 @@ Section {CREATE INDEX} createindex
Syntax {sql-statement} {
CREATE [UNIQUE] INDEX <index-name>
ON <table-name> ( <column-name> [, <column-name>]* )
[ <conflict-clause> ]
[ ON CONFLICT <conflict-algorithm> ]
} {column-name} {
<name> [ ASC | DESC ]
}
@@ -282,6 +261,8 @@ DEFAULT <value>
PRIMARY KEY ( <name> [, <name>]* ) [ <conflict-clause> ]|
UNIQUE ( <name> [, <name>]* ) [ <conflict-clause> ] |
CHECK ( <expr> ) [ <conflict-clause> ]
} {conflict-clause} {
ON CONFLICT <conflict-algorithm>
}
puts {
@@ -563,8 +544,8 @@ The "<b>count(*)</b>" syntax is supported but
Section INSERT insert
Syntax {sql-statement} {
INSERT [ <conflict-clause> ] INTO <table-name> [( <column-list> )] VALUES ( <value-list> ) |
INSERT [ <conflict-clause> ] INTO <table-name> [( <column-list> )] <select-statement>
INSERT [OR <conflict-algorithm>] INTO <table-name> [(<column-list>)] VALUES(<value-list>) |
INSERT [OR <conflict-algorithm>] INTO <table-name> [(<column-list>)] <select-statement>
}
puts {
@@ -590,7 +571,199 @@ the ORDER BY is ignored.</p>
<p>The optional conflict-clause allows the specification of an alternative
constraint conflict resolution algorithm to use during this one command.
See the section titled
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
<a href="#conflict">ON CONFLICT</a> for additional information.
For compatibility with MySQL, the parser allows the use of the
single keyword "REPLACE" as an alias for "INSERT OR REPLACE".
</p>
}
Section {ON CONFLICT clause} conflict
Syntax {conflict-clause} {
ON CONFLICT <conflict-algorithm>
} {conflict-algorithm} {
ROLLBACK | ABORT | FAIL | IGNORE | REPLACE
}
puts {
<p>The ON CONFLICT clause is not a separate SQL command. It is a
non-standard clause that can appear in many other SQL commands.
It is given its own section in this document because it is not
part of standard SQL and therefore might not be familiar.</p>
<p>The syntax for the ON CONFLICT clause is as shown above for
the CREATE TABLE, CREATE INDEX, and BEGIN TRANSACTION commands.
For the COPY, INSERT, and UPDATE commands, the keywords
"ON CONFLICT" are replaced by "OR", to make the syntax seem more
natural. But the meaning of the clause is the same either way.</p>
<p>The ON CONFLICT clause specifies an algorithm used to resolve
constraint conflicts. There are five choices: ROLLBACK, ABORT,
FAIL, IGNORE, and REPLACE. The default algorithm is ABORT. This
is what they mean:</p>
<dl>
<dt><b>ROLLBACK</b></dt>
<dd><p>When a constraint violation occurs, an immediate ROLLBACK
occurs, thus ending the current transaction, and the command aborts
with a return code of SQLITE_CONSTRAINT. If no transaction is
active (other than the implied transaction that is created on every
command) then this algorithm works the same as ABORT.</p></dd>
<dt><b>ABORT</b></dt>
<dd><p>When a constraint violation occurs, the command backs out
any prior changes it might have made and aborts with a return code
of SQLITE_CONSTRAINT. But no ROLLBACK is executed so changes
from prior commands within the same transaction
are preserved. This is the default behavior.</p></dd>
<dt><b>FAIL</b></dt>
<dd><p>When a constraint violation occurs, the command aborts with a
return code SQLITE_CONSTRAINT. But any changes to the database that
the command made prior to encountering the constraint violation
are preserved and are not backed out. For example, if an UPDATE
statement encountered a constraint violation on the 100th row that
it attempts to update, then the first 99 row changes are preserved
by change to rows 100 and beyond never occur.</p></dd>
<dt><b>IGNORE</b></dt>
<dd><p>When a constraint violation occurs, the one row that contains
the constraint violation is not inserted or changed. But the command
continues executing normally. Other rows before and after the row that
contained the constraint violation continue to be inserted or updated
normally. No error is returned.</p></dd>
<dt><b>REPLACE</b></dt>
<dd><p>When a UNIQUE constraint violation occurs, the pre-existing row
that is causing the constraint violation is removed prior to inserting
or updating the current row. Thus the insert or update always occurs.
The command continues executing normally. No error is returned.</p></dd>
</dl>
<p>
The conflict resolution algorithm can be specified in three places,
in order from lowest to highest precedence:
</p>
<ol>
<li><p>
On a BEGIN TRANSACTION command.
</p></li>
<li><p>
On individual constraints within a CREATE TABLE or CREATE INDEX
statement.
</p></li>
<li><p>
In the OR clause of a COPY, INSERT, or UPDATE command.
</p></li>
</ol>
<p>The algorithm specified in the OR clause of a COPY, INSERT, or UPDATE
overrides any algorithm specified by a CREATE TABLE or CREATE INDEX.
The algorithm specified within a CREATE TABLE or CREATE INDEX will, in turn,
override the algorithm specified by a BEGIN TRANSACTION command.
If no algorithm is specified anywhere, the ABORT algorithm is used.</p>
}
# <p>For additional information, see
# <a href="conflict.html">conflict.html</a>.</p>
Section PRAGMA pragma
Syntax {sql-statement} {
PRAGMA <name> = <value> |
PRAGMA <function>(<arg>)
}
puts {
<p>The PRAGMA command is used to modify the operation of the SQLite library.
The pragma command is experimental and specific pragma statements may
removed or added in future releases of SQLite. Use this command
with caution.</p>
<p>The current implementation supports the following pragmas:</p>
<ul>
<li><p><b>PRAGMA cache_size = </b><i>Number-of-pages</i><b>;</b></p>
<p>Change the maximum number of database disk pages that SQLite
will hold in memory at once. Each page uses about 1.5K of RAM.
The default cache size is 100. If you are doing UPDATEs or DELETEs
that change many rows of a database and you do not mind if SQLite
uses more memory, you can increase the cache size for a possible speed
improvement.</p></li>
<li><p><b>PRAGMA count_changes = ON;
<br>PRAGMA count_changes = OFF;</b></p>
<p>When on, the COUNT_CHANGES pragma causes the callback function to
be invoked once for each DELETE, INSERT, or UPDATE operation. The
argument is the number of rows that were changed.</p>
<li><p><b>PRAGMA empty_result_callbacks = ON;
<br>PRAGMA empty_result_callbacks = OFF;</b></p>
<p>When on, the EMPTY_RESULT_CALLBACKS pragma causes the callback
function to be invoked once for each query that has an empty result
set. The third "<b>argv</b>" parameter to the callback is set to NULL
because there is no data to report. But the second "<b>argc</b>" and
fourth "<b>columnNames</b>" parameters are valid and can be used to
determine the number and names of the columns that would have been in
the result set had the set not been empty.</p>
<li><p><b>PRAGMA full_column_names = ON;
<br>PRAGMA full_column_names = OFF;</b></p>
<p>The column names reported in an SQLite callback are normally just
the name of the column itself, except for joins when "TABLE.COLUMN"
is used. But when full_column_names is turned on, column names are
always reported as "TABLE.COLUMN" even for simple queries.</p></li>
<li><p><b>PRAGMA index_info(</b><i>index-name</i><b>);</b></p>
<p>For each column that the named index references, invoke the
callback function
once with information about that column, including the column name,
and the column number.</p>
<li><p><b>PRAGMA index_list(</b><i>table-name</i><b>);</b></p>
<p>For each index on the named table, invoke the callback function
once with information about that index. Arguments include the
index name and a flag to indicate whether or not the index must be
unique.</p>
<li><p><b>PRAGMA parser_trace = ON;<br>PRAGMA parser_trace = OFF;</b></p>
<p>Turn tracing of the SQL parser inside of the
SQLite library on and off. This is used for debugging.
This only works if the library is compiled without the NDEBUG macro.
</p></li>
<li><p><b>PRAGMA table_info(</b><i>table-name</i><b>);</b></p>
<p>For each column in the named table, invoke the callback function
once with information about that column, including the column name,
data type, whether or not the column can be NULL, and the default
value for the column.</p>
<li><p><b>PRAGMA vdbe_trace = ON;<br>PRAGMA vdbe_trace = OFF;</b></p>
<p>Turn tracing of the virtual database engine inside of the
SQLite library on and off. This is used for debugging.</p></li>
</ul>
<p>No error message is generated if an unknown pragma is issued.
Unknown pragmas are ignored.</p>
}
Section REPLACE replace
Syntax {sql-statement} {
REPLACE INTO <table-name> [( <column-list> )] VALUES ( <value-list> ) |
REPLACE INTO <table-name> [( <column-list> )] <select-statement>
}
puts {
<p>The REPLACE command is an alias for the "INSERT OR REPLACE" variant
of the <a href="#insert">INSERT command</a>. This alias is provided for
compatibility with MySQL. See the
<a href="#insert">INSERT command</a> documentation for additional
information.</p>
}
Section SELECT select
@@ -675,7 +848,7 @@ are connected into a compound, they group from left to right.</p>
Section UPDATE update
Syntax {sql-statement} {
UPDATE [ <conflict-clause> ] <table-name>
UPDATE [ OR <conflict-algorithm> ] <table-name>
SET <assignment> [, <assignment>]
[WHERE <expression>]
} {assignment} {
@@ -713,89 +886,6 @@ the database backend and VACUUM has become a no-op.
</p>
}
Section PRAGMA pragma
Syntax {sql-statement} {
PRAGMA <name> = <value> |
PRAGMA <function>(<arg>)
}
puts {
<p>The PRAGMA command is used to modify the operation of the SQLite library.
The pragma command is experimental and specific pragma statements may
removed or added in future releases of SQLite. Use this command
with caution.</p>
<p>The current implementation supports the following pragmas:</p>
<ul>
<li><p><b>PRAGMA cache_size = </b><i>Number-of-pages</i><b>;</b></p>
<p>Change the maximum number of database disk pages that SQLite
will hold in memory at once. Each page uses about 1.5K of RAM.
The default cache size is 100. If you are doing UPDATEs or DELETEs
that change many rows of a database and you do not mind if SQLite
uses more memory, you can increase the cache size for a possible speed
improvement.</p></li>
<li><p><b>PRAGMA count_changes = ON;
<br>PRAGMA count_changes = OFF;</b></p>
<p>When on, the COUNT_CHANGES pragma causes the callback function to
be invoked once for each DELETE, INSERT, or UPDATE operation. The
argument is the number of rows that were changed.</p>
<li><p><b>PRAGMA empty_result_callbacks = ON;
<br>PRAGMA empty_result_callbacks = OFF;</b></p>
<p>When on, the EMPTY_RESULT_CALLBACKS pragma causes the callback
function to be invoked once for each query that has an empty result
set. The third "<b>argv</b>" parameter to the callback is set to NULL
because there is no data to report. But the second "<b>argc</b>" and
fourth "<b>columnNames</b>" parameters are valid and can be used to
determine the number and names of the columns that would have been in
the result set had the set not been empty.</p>
<li><p><b>PRAGMA full_column_names = ON;
<br>PRAGMA full_column_names = OFF;</b></p>
<p>The column names reported in an SQLite callback are normally just
the name of the column itself, except for joins when "TABLE.COLUMN"
is used. But when full_column_names is turned on, column names are
always reported as "TABLE.COLUMN" even for simple queries.</p></li>
<li><p><b>PRAGMA index_info(</b><i>index-name</i><b>);</b></p>
<p>For each column that the named index references, invoke the
callback function
once with information about that column, including the column name,
and the column number.</p>
<li><p><b>PRAGMA index_list(</b><i>table-name</i><b>);</b></p>
<p>For each index on the named table, invoke the callback function
once with information about that index. Arguments include the
index name and a flag to indicate whether or not the index must be
unique.</p>
<li><p><b>PRAGMA parser_trace = ON;<br>PRAGMA parser_trace = OFF;</b></p>
<p>Turn tracing of the SQL parser inside of the
SQLite library on and off. This is used for debugging.
This only works if the library is compiled without the NDEBUG macro.
</p></li>
<li><p><b>PRAGMA table_info(</b><i>table-name</i><b>);</b></p>
<p>For each column in the named table, invoke the callback function
once with information about that column, including the column name,
data type, whether or not the column can be NULL, and the default
value for the column.</p>
<li><p><b>PRAGMA vdbe_trace = ON;<br>PRAGMA vdbe_trace = OFF;</b></p>
<p>Turn tracing of the virtual database engine inside of the
SQLite library on and off. This is used for debugging.</p></li>
</ul>
<p>No error message is generated if an unknown pragma is issued.
Unknown pragmas are ignored.</p>
}
puts {
<p></p>
}
puts {
<p><hr /></p>