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:
26
manifest
26
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Get\sthe\sABORT\sconflict\sresolution\salgorithm\sworking.\s(CVS\s362)
|
C Five-algorithm\sconflict\sresolution\sappears\sto\sbe\sworking.\s(CVS\s363)
|
||||||
D 2002-02-02T18:49:20
|
D 2002-02-03T00:56:10
|
||||||
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
|
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
|
||||||
F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
|
F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
|
||||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||||
@@ -19,21 +19,21 @@ F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1
|
|||||||
F publish.sh 5b59f4aff037aafa0e4a3b6fa599495dbd73f360
|
F publish.sh 5b59f4aff037aafa0e4a3b6fa599495dbd73f360
|
||||||
F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
|
F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
|
||||||
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
||||||
F src/btree.c 94deba286af8e1f665d98378c099da2f7455f291
|
F src/btree.c ba5712cf620f80055948cc41157e14eab6ceee86
|
||||||
F src/btree.h a94bef69f5174461331b6b9ae45a2d84f05af6db
|
F src/btree.h a94bef69f5174461331b6b9ae45a2d84f05af6db
|
||||||
F src/build.c 397d78ce466e3c22d56de85ae23d8a2777d3b9e6
|
F src/build.c 0c7346d0522e59be67a4bb841020540d8ba5d136
|
||||||
F src/delete.c f8ad71be53cf18656b6573de65395852fe817f0c
|
F src/delete.c f8ad71be53cf18656b6573de65395852fe817f0c
|
||||||
F src/expr.c a2a87dbd411a508ff89dffa90505ad42dac2f920
|
F src/expr.c a2a87dbd411a508ff89dffa90505ad42dac2f920
|
||||||
F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46
|
F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46
|
||||||
F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
|
F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
|
||||||
F src/insert.c 051e909cf4c8505aae930dcd773215404e187f23
|
F src/insert.c 173da7b06fe9282e0f529ff1e599460304ceeb23
|
||||||
F src/main.c 300320ba68d3e5b22c2c5b2c07fa884878202181
|
F src/main.c 300320ba68d3e5b22c2c5b2c07fa884878202181
|
||||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||||
F src/os.c 1953080d14098cd45e5bde88941567688efb72b1
|
F src/os.c 1953080d14098cd45e5bde88941567688efb72b1
|
||||||
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
|
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
|
||||||
F src/pager.c 4059bda97a7e10083b77b7d347fea45426b08589
|
F src/pager.c 4059bda97a7e10083b77b7d347fea45426b08589
|
||||||
F src/pager.h b28f004e2f5541dc60cc32db01bf80cf4d056283
|
F src/pager.h b28f004e2f5541dc60cc32db01bf80cf4d056283
|
||||||
F src/parse.y 88856227ae8472d0f4ae8514bc9561a6ca060690
|
F src/parse.y f081d7d4ef17deb2e20511addd32d07e277edc25
|
||||||
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
|
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
|
||||||
F src/random.c f6b36bec5ebd3edb3440224bf5bf811fe4ac9a1b
|
F src/random.c f6b36bec5ebd3edb3440224bf5bf811fe4ac9a1b
|
||||||
F src/select.c fc11d5a8c2bae1b62d8028ffb111c773ad6bf161
|
F src/select.c fc11d5a8c2bae1b62d8028ffb111c773ad6bf161
|
||||||
@@ -49,7 +49,7 @@ F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b
|
|||||||
F src/tokenize.c 01a09db6adf933e941db1b781789a0c175be6504
|
F src/tokenize.c 01a09db6adf933e941db1b781789a0c175be6504
|
||||||
F src/update.c 95459f94a061860bf8e5716b3426a5ba85c79103
|
F src/update.c 95459f94a061860bf8e5716b3426a5ba85c79103
|
||||||
F src/util.c 8f8973dd55a6ec63be9632fc5de86965c99d6327
|
F src/util.c 8f8973dd55a6ec63be9632fc5de86965c99d6327
|
||||||
F src/vdbe.c 3e9d9dba06fb7f6fe85ca3c345eedd32bf27f3a7
|
F src/vdbe.c df1c920e74b2cd76d763833a655fbabb67f17237
|
||||||
F src/vdbe.h 3791edabb212038ae5fbcfa72580204596be01a7
|
F src/vdbe.h 3791edabb212038ae5fbcfa72580204596be01a7
|
||||||
F src/where.c 2dda39367f193194e4c7d2e0dcab31527d9d8aba
|
F src/where.c 2dda39367f193194e4c7d2e0dcab31527d9d8aba
|
||||||
F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
|
F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
|
||||||
@@ -57,7 +57,7 @@ F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
|||||||
F test/btree.test 6ab4dc5f595905a276ef588fad3c9236dc07a47b
|
F test/btree.test 6ab4dc5f595905a276ef588fad3c9236dc07a47b
|
||||||
F test/btree2.test 08e9485619265cbaf5d11bd71f357cdc26bb87e0
|
F test/btree2.test 08e9485619265cbaf5d11bd71f357cdc26bb87e0
|
||||||
F test/btree3.test 9caa9e22491dd8cd8aa36d7ac3b48b089817c895
|
F test/btree3.test 9caa9e22491dd8cd8aa36d7ac3b48b089817c895
|
||||||
F test/conflict.test 70d40d77bb83f326574488d3cde1d0f3c51a0949
|
F test/conflict.test dd1b380595bb48b90289d761f4d11a46d7c60178
|
||||||
F test/copy.test 9ff0063c0b95b3d51b8d0c7fe0ff51dabaa66549
|
F test/copy.test 9ff0063c0b95b3d51b8d0c7fe0ff51dabaa66549
|
||||||
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
|
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
|
||||||
F test/expr.test c8a495050dcec3f9e68538c3ef466726933302c1
|
F test/expr.test c8a495050dcec3f9e68538c3ef466726933302c1
|
||||||
@@ -108,21 +108,21 @@ F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
|||||||
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
||||||
F www/c_interface.tcl 82a026b1681757f13b3f62e035f3a31407c1d353
|
F www/c_interface.tcl 82a026b1681757f13b3f62e035f3a31407c1d353
|
||||||
F www/changes.tcl 5c3b5b80d7144d46f100f333d4cab6184828a6c2
|
F www/changes.tcl 5c3b5b80d7144d46f100f333d4cab6184828a6c2
|
||||||
F www/conflict.tcl 3f70c01680b8d763bf3305eb67f6d85fdf83b497
|
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
||||||
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
||||||
F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0
|
F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0
|
||||||
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
||||||
F www/faq.tcl 32cbc134879871604070d4cc3a32e73fb22a35f9
|
F www/faq.tcl 32cbc134879871604070d4cc3a32e73fb22a35f9
|
||||||
F www/formatchng.tcl 2d9a35c787823b48d72a5c64bb5414a43e26d5ad
|
F www/formatchng.tcl 2d9a35c787823b48d72a5c64bb5414a43e26d5ad
|
||||||
F www/index.tcl 748614d8208c761ed3840e7958b8eed04de81822
|
F www/index.tcl 748614d8208c761ed3840e7958b8eed04de81822
|
||||||
F www/lang.tcl 7ad595247fd81f394012a0cfd84ccd6241b9e59a
|
F www/lang.tcl 260f3f9015344634ed9c2518f9a856462d37d6a6
|
||||||
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
|
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
|
||||||
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
|
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
|
||||||
F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
|
F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
|
||||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||||
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
||||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||||
P aaa53e113ef849e34883ead8ae584c722ad967db
|
P 9be4d4c6f12056782966396dca0b8e2d384d0cf2
|
||||||
R f2763ccecef4a6c8cd264dd83b3c6a22
|
R 60fe69f0169f5844176ca5b7853e2e65
|
||||||
U drh
|
U drh
|
||||||
Z fb37183391242f0b96b036b1bf3ee1ea
|
Z fa5a72d3a4d7961b510d6a8d5ba99c2c
|
||||||
|
@@ -1 +1 @@
|
|||||||
9be4d4c6f12056782966396dca0b8e2d384d0cf2
|
0115518f8e4591123582e3d2bb67282111ebcf60
|
@@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** 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.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** For a detailed discussion of BTrees, refer to
|
** For a detailed discussion of BTrees, refer to
|
||||||
@@ -816,7 +816,9 @@ int sqliteBtreeRollback(Btree *pBt){
|
|||||||
*/
|
*/
|
||||||
int sqliteBtreeBeginCkpt(Btree *pBt){
|
int sqliteBtreeBeginCkpt(Btree *pBt){
|
||||||
int rc;
|
int rc;
|
||||||
if( !pBt->inTrans || pBt->inCkpt ) return SQLITE_ERROR;
|
if( !pBt->inTrans || pBt->inCkpt ){
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
rc = sqlitepager_ckpt_begin(pBt->pPager);
|
rc = sqlitepager_ckpt_begin(pBt->pPager);
|
||||||
pBt->inCkpt = 1;
|
pBt->inCkpt = 1;
|
||||||
return rc;
|
return rc;
|
||||||
@@ -834,6 +836,7 @@ int sqliteBtreeCommitCkpt(Btree *pBt){
|
|||||||
}else{
|
}else{
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
pBt->inCkpt = 0;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -856,6 +859,7 @@ int sqliteBtreeRollbackCkpt(Btree *pBt){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc = sqlitepager_ckpt_rollback(pBt->pPager);
|
rc = sqlitepager_ckpt_rollback(pBt->pPager);
|
||||||
|
pBt->inCkpt = 0;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
** PRAGMA
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -518,7 +518,6 @@ void sqliteAddNotNull(Parse *pParse, int onError){
|
|||||||
int i;
|
int i;
|
||||||
if( (p = pParse->pNewTable)==0 ) return;
|
if( (p = pParse->pNewTable)==0 ) return;
|
||||||
i = p->nCol-1;
|
i = p->nCol-1;
|
||||||
if( onError==OE_Default ) onError = OE_Abort;
|
|
||||||
if( i>=0 ) p->aCol[i].notNull = onError;
|
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 ){
|
if( iCol>=0 && iCol<pTab->nCol ){
|
||||||
zType = pTab->aCol[iCol].zType;
|
zType = pTab->aCol[iCol].zType;
|
||||||
}
|
}
|
||||||
if( onError==OE_Default ) onError = OE_Abort;
|
|
||||||
if( pParse->db->file_format>=1 &&
|
if( pParse->db->file_format>=1 &&
|
||||||
zType && sqliteStrICmp(zType, "INTEGER")==0 ){
|
zType && sqliteStrICmp(zType, "INTEGER")==0 ){
|
||||||
pTab->iPKey = iCol;
|
pTab->iPKey = iCol;
|
||||||
@@ -854,7 +852,6 @@ void sqliteCreateIndex(
|
|||||||
int hideName = 0; /* Do not put table name in the hash table */
|
int hideName = 0; /* Do not put table name in the hash table */
|
||||||
|
|
||||||
if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
|
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.
|
** Find the table that is to be indexed. Return early if not found.
|
||||||
|
57
src/insert.c
57
src/insert.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -396,9 +396,6 @@ void sqliteGenerateConstraintChecks(
|
|||||||
v = sqliteGetVdbe(pParse);
|
v = sqliteGetVdbe(pParse);
|
||||||
assert( v!=0 );
|
assert( v!=0 );
|
||||||
nCol = pTab->nCol;
|
nCol = pTab->nCol;
|
||||||
if( overrideError==OE_Default ){
|
|
||||||
overrideError = pParse->db->onError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test all NOT NULL constraints.
|
/* Test all NOT NULL constraints.
|
||||||
*/
|
*/
|
||||||
@@ -412,7 +409,8 @@ void sqliteGenerateConstraintChecks(
|
|||||||
if( overrideError!=OE_Default ){
|
if( overrideError!=OE_Default ){
|
||||||
onError = overrideError;
|
onError = overrideError;
|
||||||
}else if( onError==OE_Default ){
|
}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 ){
|
if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){
|
||||||
onError = OE_Abort;
|
onError = OE_Abort;
|
||||||
@@ -447,35 +445,37 @@ void sqliteGenerateConstraintChecks(
|
|||||||
|
|
||||||
/* Test all UNIQUE constraints. Add index records as we go.
|
/* Test all UNIQUE constraints. Add index records as we go.
|
||||||
*/
|
*/
|
||||||
if( (recnoChng || !isUpdate) && pTab->iPKey>=0 && pTab->keyConf!=OE_Replace
|
if( (recnoChng || !isUpdate) && pTab->iPKey>=0 ){
|
||||||
&& overrideError!=OE_Replace ){
|
|
||||||
sqliteVdbeAddOp(v, OP_Dup, nCol, 1);
|
|
||||||
jumpInst = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
|
|
||||||
onError = pTab->keyConf;
|
onError = pTab->keyConf;
|
||||||
if( overrideError!=OE_Default ){
|
if( overrideError!=OE_Default ){
|
||||||
onError = overrideError;
|
onError = overrideError;
|
||||||
}else if( onError==OE_Default ){
|
}else if( onError==OE_Default ){
|
||||||
onError = OE_Abort;
|
onError = pParse->db->onError;
|
||||||
|
if( onError==OE_Default ) onError = OE_Abort;
|
||||||
}
|
}
|
||||||
switch( onError ){
|
if( onError!=OE_Replace ){
|
||||||
case OE_Rollback:
|
sqliteVdbeAddOp(v, OP_Dup, nCol, 1);
|
||||||
case OE_Abort:
|
jumpInst = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
|
||||||
case OE_Fail: {
|
switch( onError ){
|
||||||
sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
|
case OE_Rollback:
|
||||||
break;
|
case OE_Abort:
|
||||||
|
case OE_Fail: {
|
||||||
|
sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OE_Ignore: {
|
||||||
|
sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
|
||||||
|
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: assert(0);
|
||||||
}
|
}
|
||||||
case OE_Ignore: {
|
contAddr = sqliteVdbeCurrentAddr(v);
|
||||||
sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
|
sqliteVdbeChangeP2(v, jumpInst, contAddr);
|
||||||
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
if( isUpdate ){
|
||||||
break;
|
sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
|
||||||
|
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||||
}
|
}
|
||||||
default: assert(0);
|
|
||||||
}
|
|
||||||
contAddr = sqliteVdbeCurrentAddr(v);
|
|
||||||
sqliteVdbeChangeP2(v, jumpInst, contAddr);
|
|
||||||
if( isUpdate ){
|
|
||||||
sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
|
|
||||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extra = 0;
|
extra = 0;
|
||||||
@@ -497,7 +497,8 @@ void sqliteGenerateConstraintChecks(
|
|||||||
if( overrideError!=OE_Default ){
|
if( overrideError!=OE_Default ){
|
||||||
onError = overrideError;
|
onError = overrideError;
|
||||||
}else if( onError==OE_Default ){
|
}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);
|
sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1);
|
||||||
jumpInst = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);
|
jumpInst = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
** the parser. Lemon will also generate a header file containing
|
** the parser. Lemon will also generate a header file containing
|
||||||
** numeric codes for all of the tokens.
|
** 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_prefix TK_
|
||||||
%token_type {Token}
|
%token_type {Token}
|
||||||
@@ -57,10 +57,7 @@ explain ::= EXPLAIN. {pParse->explain = 1;}
|
|||||||
///////////////////// Begin and end transactions. ////////////////////////////
|
///////////////////// Begin and end transactions. ////////////////////////////
|
||||||
//
|
//
|
||||||
|
|
||||||
// For now, disable the ability to change the default conflict resolution
|
cmd ::= BEGIN trans_opt onconf(R). {sqliteBeginTransaction(pParse,R);}
|
||||||
// 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);}
|
|
||||||
trans_opt ::= .
|
trans_opt ::= .
|
||||||
trans_opt ::= TRANSACTION.
|
trans_opt ::= TRANSACTION.
|
||||||
trans_opt ::= TRANSACTION ids.
|
trans_opt ::= TRANSACTION ids.
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
** But other routines are also provided to help in building up
|
** But other routines are also provided to help in building up
|
||||||
** a program instruction by instruction.
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -4511,10 +4511,9 @@ cleanup:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}
|
||||||
sqliteBtreeCommitCkpt(pBt);
|
sqliteBtreeCommitCkpt(pBt);
|
||||||
if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
|
if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* Jump to here if a malloc() fails. It's hard to get a malloc()
|
/* Jump to here if a malloc() fails. It's hard to get a malloc()
|
||||||
|
@@ -13,263 +13,368 @@
|
|||||||
# This file implements tests for the conflict resolution extension
|
# This file implements tests for the conflict resolution extension
|
||||||
# to SQLite.
|
# 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]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
# Create a table with three fields, two of which must be
|
# Create tables for the first group of tests.
|
||||||
# UNIQUE.
|
|
||||||
#
|
#
|
||||||
do_test conflict-1.1 {
|
do_test conflict-1.0 {
|
||||||
execsql {
|
execsql {
|
||||||
CREATE TABLE t1(a, b, c, UNIQUE(a,b));
|
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;
|
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 {
|
# Six columns of configuration data as follows:
|
||||||
execsql {
|
#
|
||||||
BEGIN;
|
# i The reference number of the test
|
||||||
CREATE TABLE t2(a,b,c);
|
# conf The conflict resolution algorithm on the BEGIN statement
|
||||||
INSERT INTO t2 VALUES(1,2,11);
|
# cmd An INSERT or REPLACE command to execute against table t1
|
||||||
INSERT INTO t2 VALUES(1,2,12);
|
# t0 True if there is an error from $cmd
|
||||||
INSERT INTO t2 VALUES(1,2,13);
|
# t1 Content of "c" column of t1 assuming no error in $cmd
|
||||||
INSERT INTO t2 VALUES(1,2,14);
|
# t2 Content of "x" column of t2
|
||||||
INSERT INTO t2 VALUES(1,3,21);
|
#
|
||||||
INSERT INTO t2 VALUES(1,3,22);
|
foreach {i conf cmd t0 t1 t2} {
|
||||||
INSERT INTO t2 VALUES(1,3,23);
|
1 {} INSERT 1 {} 1
|
||||||
INSERT INTO t2 VALUES(1,3,24);
|
2 {} {INSERT OR IGNORE} 0 3 1
|
||||||
COMMIT;
|
3 {} {INSERT OR REPLACE} 0 4 1
|
||||||
SELECT count(*) FROM t2;
|
4 {} REPLACE 0 4 1
|
||||||
}
|
5 {} {INSERT OR FAIL} 1 {} 1
|
||||||
} 8
|
6 {} {INSERT OR ABORT} 1 {} 1
|
||||||
do_test conflict-1.10 {
|
7 {} {INSERT OR ROLLBACK} 1 {} {}
|
||||||
catchsql {
|
8 IGNORE INSERT 0 3 1
|
||||||
INSERT OR IGNORE INTO t1 SELECT a,b,c FROM t2 ORDER BY c;
|
9 IGNORE {INSERT OR IGNORE} 0 3 1
|
||||||
SELECT c FROM t1 ORDER BY c;
|
10 IGNORE {INSERT OR REPLACE} 0 4 1
|
||||||
}
|
11 IGNORE REPLACE 0 4 1
|
||||||
} {0 {5 21}}
|
12 IGNORE {INSERT OR FAIL} 1 {} 1
|
||||||
do_test conflict-1.11 {
|
13 IGNORE {INSERT OR ABORT} 1 {} 1
|
||||||
catchsql {
|
14 IGNORE {INSERT OR ROLLBACK} 1 {} {}
|
||||||
INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c;
|
15 REPLACE INSERT 0 4 1
|
||||||
SELECT c FROM t1 ORDER BY c;
|
16 FAIL INSERT 1 {} 1
|
||||||
}
|
17 ABORT INSERT 1 {} 1
|
||||||
} {0 {14 24}}
|
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);
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
|
||||||
###### Fix me!
|
# Create tables for the first group of tests.
|
||||||
do_test conflict-1.12 {
|
#
|
||||||
catchsql {
|
do_test conflict-2.0 {
|
||||||
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;
|
|
||||||
DELETE FROM t1;
|
|
||||||
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}}
|
|
||||||
|
|
||||||
do_test conflict-2.1 {
|
|
||||||
execsql {
|
execsql {
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
DROP TABLE t2;
|
DROP TABLE t2;
|
||||||
CREATE TABLE t1(a integer primary key, b, c, UNIQUE(a,b));
|
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(a,b));
|
||||||
CREATE INDEX t1b ON t1(b);
|
CREATE TABLE t2(x);
|
||||||
CREATE INDEX t1bc ON t1(b,c);
|
|
||||||
INSERT INTO t1 VALUES(1,2,3);
|
|
||||||
SELECT c FROM t1 ORDER BY c;
|
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 {
|
# 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);
|
||||||
|
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 {
|
execsql {
|
||||||
BEGIN;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t2(a,b,c INTEGER PRIMARY KEY);
|
DROP TABLE t2;
|
||||||
INSERT INTO t2 VALUES(1,2,11);
|
CREATE TABLE t1(a, b, c INTEGER PRIMARY KEY, UNIQUE(a,b));
|
||||||
INSERT INTO t2 VALUES(1,2,12);
|
CREATE TABLE t2(x);
|
||||||
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;
|
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!
|
# Six columns of configuration data as follows:
|
||||||
do_test conflict-2.12 {
|
#
|
||||||
catchsql {
|
# i The reference number of the test
|
||||||
INSERT OR REPLACE INTO t1 SELECT a,b,c FROM t2 ORDER BY c DESC;
|
# conf The conflict resolution algorithm on the BEGIN statement
|
||||||
SELECT c FROM t1 ORDER BY c;
|
# cmd An INSERT or REPLACE command to execute against table t1
|
||||||
}
|
# t0 True if there is an error from $cmd
|
||||||
} {0 {14 24}}
|
# 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-2.13 {
|
do_test conflict-4.0 {
|
||||||
execsql {
|
execsql {
|
||||||
BEGIN;
|
DROP TABLE t2;
|
||||||
DELETE FROM t1;
|
CREATE TABLE t2(x);
|
||||||
INSERT INTO t1 VALUES(1,2,3);
|
SELECT x FROM t2;
|
||||||
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 {
|
# Six columns of configuration data as follows:
|
||||||
UPDATE OR ABORT t1 SET a=2, b=3 WHERE b=2;
|
#
|
||||||
SELECT c FROM t1 ORDER BY c;
|
# 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;
|
||||||
}
|
}
|
||||||
} {1 {constraint failed}};
|
} {}
|
||||||
do_test conflict-2.15 {
|
|
||||||
catchsql {
|
# Six columns of configuration data as follows:
|
||||||
UPDATE t1 SET a=2, b=3 WHERE b=2;
|
#
|
||||||
SELECT c FROM t1 ORDER BY c;
|
# 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);
|
||||||
}
|
}
|
||||||
} {1 {constraint failed}};
|
} {1 2 1 4}
|
||||||
do_test conflict-2.16 {
|
|
||||||
catchsql {
|
# Six columns of configuration data as follows:
|
||||||
UPDATE OR IGNORE t1 SET a=2, b=3 WHERE b=2;
|
#
|
||||||
SELECT * FROM t1 ORDER BY c;
|
# i The reference number of the test
|
||||||
}
|
# conf1 The conflict resolution algorithm on the UNIQUE constraint
|
||||||
} {0 {1 2 3 2 3 4 3 3 5}}
|
# conf2 The conflict resolution algorithm on the BEGIN statement
|
||||||
do_test conflict-2.17 {
|
# cmd An UPDATE command to execute against table t1
|
||||||
catchsql {
|
# t0 True if there is an error from $cmd
|
||||||
UPDATE OR REPLACE t1 SET a=2, b=3 WHERE b=2;
|
# t1 Content of "b" column of t1 assuming no error in $cmd
|
||||||
SELECT * FROM t1 ORDER BY c;
|
# t2 Content of "x" column of t3
|
||||||
}
|
#
|
||||||
} {0 {2 3 3 3 3 5}}
|
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
|
finish_test
|
||||||
|
208
www/conflict.tcl
208
www/conflict.tcl
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this Tcl script to generate the constraint.html file.
|
# 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>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -22,7 +22,8 @@ puts {
|
|||||||
In most SQL databases, if you have a UNIQUE constraint on
|
In most SQL databases, if you have a UNIQUE constraint on
|
||||||
a table and you try to do an UPDATE or INSERT that violates
|
a table and you try to do an UPDATE or INSERT that violates
|
||||||
that constraint, the database will aborts the operation in
|
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.
|
This is the default behavior of SQLite.
|
||||||
Beginning with version 2.3.0, though, SQLite allows you to
|
Beginning with version 2.3.0, though, SQLite allows you to
|
||||||
define alternative ways for dealing with constraint violations.
|
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>
|
<h2>Conflict Resolution Algorithms</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The default conflict resolution algorithm is to abort the
|
SQLite defines five constraint conflict resolution algorithms
|
||||||
operation in progress, rollback all changes, and cancel the
|
as follows:
|
||||||
current transaction. Call this algorithm "ABORT". Abort
|
|
||||||
is the standard way of dealing with a constraint error
|
|
||||||
in most SQL databases.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<dl>
|
||||||
Sometimes ABORT is not the most helpful way of dealing
|
<dt><b>ROLLBACK</b></dt>
|
||||||
with constraint violations. Suppose, for example, you are
|
<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
|
inserting 1000 records into a database, all within a single
|
||||||
transaction, but one of those records is malformed and causes
|
transaction, but one of those records is malformed and causes
|
||||||
a constraint error. With the default ABORT behavior, none
|
a constraint error. Under PostgreSQL or Oracle, none of the
|
||||||
of the 1000 records gets inserted. But sometimes it is
|
1000 records would get inserted. In MySQL, some subset of the
|
||||||
desirable to just omit the single malformed insert and
|
records that appeared before the malformed record would be inserted
|
||||||
finish the other 999.
|
but the rest would not. Neither behavior is espeically helpful.
|
||||||
</p>
|
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 {
|
puts {
|
||||||
|
356
www/lang.tcl
356
www/lang.tcl
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this Tcl script to generate the sqlite.html file.
|
# 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>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -42,6 +42,7 @@ foreach {section} [lsort -index 0 -dictionary {
|
|||||||
{{DROP TABLE} droptable}
|
{{DROP TABLE} droptable}
|
||||||
{{DROP INDEX} dropindex}
|
{{DROP INDEX} dropindex}
|
||||||
{INSERT insert}
|
{INSERT insert}
|
||||||
|
{REPLACE replace}
|
||||||
{DELETE delete}
|
{DELETE delete}
|
||||||
{UPDATE update}
|
{UPDATE update}
|
||||||
{SELECT select}
|
{SELECT select}
|
||||||
@@ -61,7 +62,7 @@ the sequel.</p>
|
|||||||
}
|
}
|
||||||
|
|
||||||
proc Syntax {args} {
|
proc Syntax {args} {
|
||||||
puts {<table cellpadding="15">}
|
puts {<table cellpadding="10">}
|
||||||
foreach {rule body} $args {
|
foreach {rule body} $args {
|
||||||
puts "<tr><td align=\"right\" valign=\"top\">"
|
puts "<tr><td align=\"right\" valign=\"top\">"
|
||||||
puts "<i><font color=\"#ff3434\">$rule</font></i> ::=</td>"
|
puts "<i><font color=\"#ff3434\">$rule</font></i> ::=</td>"
|
||||||
@@ -105,7 +106,7 @@ proc Example {text} {
|
|||||||
Section {BEGIN TRANSACTION} createindex
|
Section {BEGIN TRANSACTION} createindex
|
||||||
|
|
||||||
Syntax {sql-statement} {
|
Syntax {sql-statement} {
|
||||||
BEGIN [TRANSACTION [<name>]]
|
BEGIN [TRANSACTION [<name>]] [ON CONFLICT <conflict-algorithm>]
|
||||||
}
|
}
|
||||||
Syntax {sql-statement} {
|
Syntax {sql-statement} {
|
||||||
END [TRANSACTION [<name>]]
|
END [TRANSACTION [<name>]]
|
||||||
@@ -119,9 +120,7 @@ ROLLBACK [TRANSACTION [<name>]]
|
|||||||
|
|
||||||
puts {
|
puts {
|
||||||
<p>Beginning in version 2.0, SQLite supports transactions with
|
<p>Beginning in version 2.0, SQLite supports transactions with
|
||||||
rollback and atomic commit. However, only a single level of
|
rollback and atomic commit.</p>
|
||||||
transaction is allowed. Transactions may not be nested.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
No changes can be made to the database except within a transaction.
|
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>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Transactions can be started manually using the BEGIN TRANSACTION
|
Transactions can be started manually using the BEGIN
|
||||||
command. Such transactions persist until a COMMIT or ROLLBACK
|
command. Such transactions usually persist until the next
|
||||||
or until an error occurs or the database is closed. If an
|
COMMIT or ROLLBACK command. But a transaction will also
|
||||||
error is encountered or the database is closed, the transaction
|
ROLLBACK if the database is closed or if an error occurs
|
||||||
is automatically rolled back. The END TRANSACTION command is
|
and the ROLLBACK conflict resolution algorithm is specified.
|
||||||
a alias for COMMIT.
|
See the documention on the <a href="#conflict">ON CONFLICT</a>
|
||||||
|
clause for additional information about the ROLLBACK
|
||||||
|
conflict resolution algorithm.
|
||||||
</p>
|
</p>
|
||||||
}
|
|
||||||
|
|
||||||
Section {ON CONFLICT clause} conflict
|
<p>
|
||||||
|
The optional ON CONFLICT clause at the end of a BEGIN statement
|
||||||
Syntax {conflict-clause} {
|
can be used to changed the default conflict resolution algorithm.
|
||||||
ON CONFLICT <algorithm>
|
The normal default is ABORT. If an alternative is specified by
|
||||||
} {algorithm} {
|
the ON CONFLICT clause of a BEGIN, then that alternative is used
|
||||||
ABORT | IGNORE | REPLACE
|
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
|
||||||
puts {
|
and by the OR clauses on COPY, INSERT, and UPDATE commands.
|
||||||
<p>The ON CONFLICT clause is not a separate SQL command. It is a
|
</p>
|
||||||
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>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Section COPY copy
|
Section COPY copy
|
||||||
|
|
||||||
Syntax {sql-statement} {
|
Syntax {sql-statement} {
|
||||||
COPY [ <conflict-clause> ] <table-name> FROM <filename>
|
COPY [ OR <conflict-algorithm> ] <table-name> FROM <filename>
|
||||||
[ USING DELIMITERS <delim> ]
|
[ USING DELIMITERS <delim> ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +198,7 @@ Section {CREATE INDEX} createindex
|
|||||||
Syntax {sql-statement} {
|
Syntax {sql-statement} {
|
||||||
CREATE [UNIQUE] INDEX <index-name>
|
CREATE [UNIQUE] INDEX <index-name>
|
||||||
ON <table-name> ( <column-name> [, <column-name>]* )
|
ON <table-name> ( <column-name> [, <column-name>]* )
|
||||||
[ <conflict-clause> ]
|
[ ON CONFLICT <conflict-algorithm> ]
|
||||||
} {column-name} {
|
} {column-name} {
|
||||||
<name> [ ASC | DESC ]
|
<name> [ ASC | DESC ]
|
||||||
}
|
}
|
||||||
@@ -282,6 +261,8 @@ DEFAULT <value>
|
|||||||
PRIMARY KEY ( <name> [, <name>]* ) [ <conflict-clause> ]|
|
PRIMARY KEY ( <name> [, <name>]* ) [ <conflict-clause> ]|
|
||||||
UNIQUE ( <name> [, <name>]* ) [ <conflict-clause> ] |
|
UNIQUE ( <name> [, <name>]* ) [ <conflict-clause> ] |
|
||||||
CHECK ( <expr> ) [ <conflict-clause> ]
|
CHECK ( <expr> ) [ <conflict-clause> ]
|
||||||
|
} {conflict-clause} {
|
||||||
|
ON CONFLICT <conflict-algorithm>
|
||||||
}
|
}
|
||||||
|
|
||||||
puts {
|
puts {
|
||||||
@@ -563,8 +544,8 @@ The "<b>count(*)</b>" syntax is supported but
|
|||||||
Section INSERT insert
|
Section INSERT insert
|
||||||
|
|
||||||
Syntax {sql-statement} {
|
Syntax {sql-statement} {
|
||||||
INSERT [ <conflict-clause> ] INTO <table-name> [( <column-list> )] VALUES ( <value-list> ) |
|
INSERT [OR <conflict-algorithm>] 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>)] <select-statement>
|
||||||
}
|
}
|
||||||
|
|
||||||
puts {
|
puts {
|
||||||
@@ -590,7 +571,199 @@ the ORDER BY is ignored.</p>
|
|||||||
<p>The optional conflict-clause allows the specification of an alternative
|
<p>The optional conflict-clause allows the specification of an alternative
|
||||||
constraint conflict resolution algorithm to use during this one command.
|
constraint conflict resolution algorithm to use during this one command.
|
||||||
See the section titled
|
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
|
Section SELECT select
|
||||||
@@ -675,7 +848,7 @@ are connected into a compound, they group from left to right.</p>
|
|||||||
Section UPDATE update
|
Section UPDATE update
|
||||||
|
|
||||||
Syntax {sql-statement} {
|
Syntax {sql-statement} {
|
||||||
UPDATE [ <conflict-clause> ] <table-name>
|
UPDATE [ OR <conflict-algorithm> ] <table-name>
|
||||||
SET <assignment> [, <assignment>]
|
SET <assignment> [, <assignment>]
|
||||||
[WHERE <expression>]
|
[WHERE <expression>]
|
||||||
} {assignment} {
|
} {assignment} {
|
||||||
@@ -713,89 +886,6 @@ the database backend and VACUUM has become a no-op.
|
|||||||
</p>
|
</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 {
|
puts {
|
||||||
<p><hr /></p>
|
<p><hr /></p>
|
||||||
|
Reference in New Issue
Block a user