Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Five-algorithm conflict resolution appears to be working. (CVS 363) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
0115518f8e4591123582e3d2bb672821 |
User & Date: | drh 2002-02-03 00:56:10.000 |
Context
2002-02-03
| ||
03:34 | The VACUUM command now does a database sanity check. (CVS 364) (check-in: 95d1f8389d user: drh tags: trunk) | |
00:56 | Five-algorithm conflict resolution appears to be working. (CVS 363) (check-in: 0115518f8e user: drh tags: trunk) | |
2002-02-02
| ||
18:49 | Get the ABORT conflict resolution algorithm working. (CVS 362) (check-in: 9be4d4c6f1 user: drh tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $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 ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
812 813 814 815 816 817 818 | ** commits or rolls back. ** ** Only one checkpoint may be active at a time. It is an error to try ** to start a new checkpoint if another checkpoint is already active. */ int sqliteBtreeBeginCkpt(Btree *pBt){ int rc; | | > > > | 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 | ** commits or rolls back. ** ** Only one checkpoint may be active at a time. It is an error to try ** to start a new checkpoint if another checkpoint is already active. */ int sqliteBtreeBeginCkpt(Btree *pBt){ int rc; if( !pBt->inTrans || pBt->inCkpt ){ return SQLITE_ERROR; } rc = sqlitepager_ckpt_begin(pBt->pPager); pBt->inCkpt = 1; return rc; } /* ** Commit a checkpoint to transaction currently in progress. If no ** checkpoint is active, this is a no-op. */ int sqliteBtreeCommitCkpt(Btree *pBt){ int rc; if( pBt->inCkpt ){ rc = sqlitepager_ckpt_commit(pBt->pPager); }else{ rc = SQLITE_OK; } pBt->inCkpt = 0; return rc; } /* ** Rollback the checkpoint to the current transaction. If there ** is no active checkpoint or transaction, this routine is a no-op. ** |
︙ | ︙ | |||
852 853 854 855 856 857 858 859 860 861 862 863 864 865 | for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( pCur->pPage ){ sqlitepager_unref(pCur->pPage); pCur->pPage = 0; } } rc = sqlitepager_ckpt_rollback(pBt->pPager); return rc; } /* ** Create a new cursor for the BTree whose root is on the page ** iTable. The act of acquiring a cursor gets a read lock on ** the database file. | > | 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( pCur->pPage ){ sqlitepager_unref(pCur->pPage); pCur->pPage = 0; } } rc = sqlitepager_ckpt_rollback(pBt->pPager); pBt->inCkpt = 0; return rc; } /* ** Create a new cursor for the BTree whose root is on the page ** iTable. The act of acquiring a cursor gets a read lock on ** the database file. |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** ** $Id: build.c,v 1.72 2002/02/03 00:56:10 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called after a single SQL statement has been ** parsed and we want to execute the VDBE code to implement |
︙ | ︙ | |||
514 515 516 517 518 519 520 | ** the column currently under construction. */ void sqliteAddNotNull(Parse *pParse, int onError){ Table *p; int i; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; | < | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | ** the column currently under construction. */ void sqliteAddNotNull(Parse *pParse, int onError){ Table *p; int i; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; if( i>=0 ) p->aCol[i].notNull = onError; } /* ** This routine is called by the parser while in the middle of ** parsing a CREATE TABLE statement. The pFirst token is the first ** token in the sequence of tokens that describe the type of the |
︙ | ︙ | |||
614 615 616 617 618 619 620 | for(iCol=0; iCol<pTab->nCol; iCol++){ if( sqliteStrICmp(pList->a[0].zName, pTab->aCol[iCol].zName)==0 ) break; } } if( iCol>=0 && iCol<pTab->nCol ){ zType = pTab->aCol[iCol].zType; } | < | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | for(iCol=0; iCol<pTab->nCol; iCol++){ if( sqliteStrICmp(pList->a[0].zName, pTab->aCol[iCol].zName)==0 ) break; } } if( iCol>=0 && iCol<pTab->nCol ){ zType = pTab->aCol[iCol].zType; } if( pParse->db->file_format>=1 && zType && sqliteStrICmp(zType, "INTEGER")==0 ){ pTab->iPKey = iCol; pTab->keyConf = onError; }else{ sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0); } |
︙ | ︙ | |||
850 851 852 853 854 855 856 | char *zName = 0; int i, j; Token nullId; /* Fake token for an empty ID list */ sqlite *db = pParse->db; int hideName = 0; /* Do not put table name in the hash table */ if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; | < | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 | char *zName = 0; int i, j; Token nullId; /* Fake token for an empty ID list */ sqlite *db = pParse->db; int hideName = 0; /* Do not put table name in the hash table */ if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; /* ** Find the table that is to be indexed. Return early if not found. */ if( pTable!=0 ){ assert( pName!=0 ); pTab = sqliteTableFromToken(pParse, pTable); |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** ** $Id: insert.c,v 1.41 2002/02/03 00:56:10 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is call to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST) |
︙ | ︙ | |||
392 393 394 395 396 397 398 | int jumpInst; int contAddr; int hasTwoRecnos = (isUpdate && recnoChng); v = sqliteGetVdbe(pParse); assert( v!=0 ); nCol = pTab->nCol; | < < < | > | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | int jumpInst; int contAddr; int hasTwoRecnos = (isUpdate && recnoChng); v = sqliteGetVdbe(pParse); assert( v!=0 ); nCol = pTab->nCol; /* Test all NOT NULL constraints. */ for(i=0; i<nCol; i++){ if( i==pTab->iPKey ){ /* Fix me: Make sure the INTEGER PRIMARY KEY is not NULL. */ continue; } onError = pTab->aCol[i].notNull; if( onError==OE_None ) continue; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = pParse->db->onError; if( onError==OE_Default ) onError = OE_Abort; } if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){ onError = OE_Abort; } sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1); addr = sqliteVdbeAddOp(v, OP_NotNull, 0, 0); switch( onError ){ |
︙ | ︙ | |||
443 444 445 446 447 448 449 | } /* Test all CHECK constraints */ /* Test all UNIQUE constraints. Add index records as we go. */ | | < < < | > > > > | | | | | | | | | | | | | | | | | | | > | 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | } /* Test all CHECK constraints */ /* Test all UNIQUE constraints. Add index records as we go. */ if( (recnoChng || !isUpdate) && pTab->iPKey>=0 ){ onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ 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: 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); } contAddr = sqliteVdbeCurrentAddr(v); sqliteVdbeChangeP2(v, jumpInst, contAddr); if( isUpdate ){ sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); 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; extra++; sqliteVdbeAddOp(v, OP_Dup, nCol+extra, 1); |
︙ | ︙ | |||
493 494 495 496 497 498 499 | } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); onError = pIdx->onError; if( onError==OE_None ) continue; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ | | > | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); onError = pIdx->onError; if( onError==OE_None ) continue; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ 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); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** ** @(#) $Id: parse.y,v 1.47 2002/02/03 00:56:10 drh Exp $ */ %token_prefix TK_ %token_type {Token} %default_type {Token} %extra_argument {Parse *pParse} %syntax_error { sqliteSetString(&pParse->zErrMsg,"syntax error",0); |
︙ | ︙ | |||
53 54 55 56 57 58 59 | ecmd ::= cmd. {sqliteExec(pParse);} ecmd ::= . explain ::= EXPLAIN. {pParse->explain = 1;} ///////////////////// Begin and end transactions. //////////////////////////// // | < < | < | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | ecmd ::= cmd. {sqliteExec(pParse);} ecmd ::= . explain ::= EXPLAIN. {pParse->explain = 1;} ///////////////////// Begin and end transactions. //////////////////////////// // cmd ::= BEGIN trans_opt onconf(R). {sqliteBeginTransaction(pParse,R);} trans_opt ::= . trans_opt ::= TRANSACTION. trans_opt ::= TRANSACTION ids. cmd ::= COMMIT trans_opt. {sqliteCommitTransaction(pParse);} cmd ::= END trans_opt. {sqliteCommitTransaction(pParse);} cmd ::= ROLLBACK trans_opt. {sqliteRollbackTransaction(pParse);} |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.115 2002/02/03 00:56:10 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test |
︙ | ︙ | |||
4507 4508 4509 4510 4511 4512 4513 | sqliteCommitInternalChanges(db); db->flags &= ~SQLITE_InTrans; db->onError = OE_Default; } break; } } | < > | | < | 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 | sqliteCommitInternalChanges(db); db->flags &= ~SQLITE_InTrans; db->onError = OE_Default; } break; } } } sqliteBtreeCommitCkpt(pBt); if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp); return rc; /* Jump to here if a malloc() fails. It's hard to get a malloc() ** to fail on a modern VM computer, so this code is untested. */ no_mem: sqliteSetString(pzErrMsg, "out of memory", 0); |
︙ | ︙ |
Changes to test/conflict.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for the conflict resolution extension # to SQLite. # | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < > < < | < < | < > > > | > > > > > | > > | < < < < < > > > > > > > > > | < > > > > > | < < | > | < | | | | < < < | | > | > | > > | | > > | | < > > > > | < < < < | < > | < > | > > > > > | > > | < < < | | | | | | | > | < | | | | < | < < < < > < < < | < | > | | | > > > > | < < | < > | > > | | > | | | | < < | < < < < | > > > > > > > | > | < > > > > > > > > > > > > > | | | > > | | > | > > > > > | > > | > > > | | | | < > > | < < | < < | | > > | < < < < < | < | < < > > | | > > > > > > > > > > > > > > > > > > | > > | | | | | > | | < < < | | > > > > > > > > > > | | > > > > | < < < < < | < | < < < > > > | < | > > > > > > > | > | < | | > > > > > > > > > | > > > | > > | | > | | | | > | > | > > | | | | > | > > > > | > > | < < < < | > > | | | > > > > > > > > > > > > > > > > > > > | | > > > > > > > > | | | > > | > > > > > > | > > | > > > | < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for the conflict resolution extension # to SQLite. # # $Id: conflict.test,v 1.5 2002/02/03 00:56:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create tables for the first group of tests. # do_test conflict-1.0 { execsql { CREATE TABLE t1(a, b, c, UNIQUE(a,b)); CREATE TABLE t2(x); 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-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] } # 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 TABLE t2(x); 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-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 { 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; } } {} # 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; } } {} # 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; } } {} # 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); } } {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 |
Changes to www/conflict.tcl.
1 2 3 | # # Run this Tcl script to generate the constraint.html file. # | | | > | < < < | | < > | < | < < < > | | < < < > | < > | < < < < < < | < | < < < < < < < < > > > > | | | < < < < < < < < < > < < < | | < | < < < | < < < < < < | < > < < < < < < | < < | < < | < | < | < | < < < | < < < < | < | < | | < > > > > < < < < < < < < < < < < | < | < < | < < < < | < < | | > > > | < | < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | # # Run this Tcl script to generate the constraint.html file. # set rcsid {$Id: conflict.tcl,v 1.2 2002/02/03 00:56:11 drh Exp $ } puts {<html> <head> <title>Constraint Conflict Resolution in SQLite</title> </head> <body bgcolor=white> <h1 align=center> Constraint Conflict Resolution in SQLite </h1>} puts "<p align=center> (This page was last modified on [lrange $rcsid 3 4] UTC) </p>" puts { <h2>Introduction</h2> <p> 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, 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. This article describes those alternatives and how to use them. </p> <h2>Conflict Resolution Algorithms</h2> <p> SQLite defines five constraint conflict resolution algorithms as follows: </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 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. 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> } puts { <p><hr /></p> <p><a href="index.html"><img src="/goback.jpg" border=0 /> Back to the SQLite Home Page</a> </p> </body></html>} |
Changes to www/lang.tcl.
1 2 3 | # # Run this Tcl script to generate the sqlite.html file. # | | | 1 2 3 4 5 6 7 8 9 10 11 | # # Run this Tcl script to generate the sqlite.html file. # set rcsid {$Id: lang.tcl,v 1.21 2002/02/03 00:56:11 drh Exp $} puts {<html> <head> <title>Query Language Understood By SQLite</title> </head> <body bgcolor=white> <h1 align=center> |
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | foreach {section} [lsort -index 0 -dictionary { {{CREATE TABLE} createtable} {{CREATE INDEX} createindex} {VACUUM vacuum} {{DROP TABLE} droptable} {{DROP INDEX} dropindex} {INSERT insert} {DELETE delete} {UPDATE update} {SELECT select} {COPY copy} {EXPLAIN explain} {expression expr} {{BEGIN TRANSACTION} transaction} {PRAGMA pragma} {{ON CONFLICT clause} conflict} }] { puts "<li><a href=\"#[lindex $section 1]\">[lindex $section 0]</a></li>" } puts {</ul></p> <p>Details on the implementation of each command are provided in the sequel.</p> } proc Syntax {args} { | > | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | foreach {section} [lsort -index 0 -dictionary { {{CREATE TABLE} createtable} {{CREATE INDEX} createindex} {VACUUM vacuum} {{DROP TABLE} droptable} {{DROP INDEX} dropindex} {INSERT insert} {REPLACE replace} {DELETE delete} {UPDATE update} {SELECT select} {COPY copy} {EXPLAIN explain} {expression expr} {{BEGIN TRANSACTION} transaction} {PRAGMA pragma} {{ON CONFLICT clause} conflict} }] { puts "<li><a href=\"#[lindex $section 1]\">[lindex $section 0]</a></li>" } puts {</ul></p> <p>Details on the implementation of each command are provided in the sequel.</p> } proc Syntax {args} { puts {<table cellpadding="10">} foreach {rule body} $args { puts "<tr><td align=\"right\" valign=\"top\">" puts "<i><font color=\"#ff3434\">$rule</font></i> ::=</td>" regsub -all < $body {%LT} body regsub -all > $body {%GT} body regsub -all %LT $body {</font></b><i><font color="#ff3434">} body regsub -all %GT $body {</font></i><b><font color="#2c2cf0">} body |
︙ | ︙ | |||
101 102 103 104 105 106 107 | proc Example {text} { puts "<blockquote><pre>$text</pre></blockquote>" } Section {BEGIN TRANSACTION} createindex Syntax {sql-statement} { | | | < < | | | | | > | > | | | | < < < < < | < | < < < | | | < < < < < < < | < < < < | < < | | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | proc Example {text} { puts "<blockquote><pre>$text</pre></blockquote>" } Section {BEGIN TRANSACTION} createindex Syntax {sql-statement} { BEGIN [TRANSACTION [<name>]] [ON CONFLICT <conflict-algorithm>] } Syntax {sql-statement} { END [TRANSACTION [<name>]] } Syntax {sql-statement} { COMMIT [TRANSACTION [<name>]] } Syntax {sql-statement} { ROLLBACK [TRANSACTION [<name>]] } puts { <p>Beginning in version 2.0, SQLite supports transactions with rollback and atomic commit.</p> <p> No changes can be made to the database except within a transaction. Any command that changes the database (basically, any SQL command other than SELECT) will automatically starts a transaction if one is not already in effect. Automatically stared transactions are committed at the conclusion of the command. </p> <p> 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> <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 [ OR <conflict-algorithm> ] <table-name> FROM <filename> [ USING DELIMITERS <delim> ] } puts { <p>The COPY command is an extension used to load large amounts of data into a table. It is modeled after a similar command found |
︙ | ︙ | |||
215 216 217 218 219 220 221 | puts "\"[Operator \\.]\".</p>" Section {CREATE INDEX} createindex Syntax {sql-statement} { CREATE [UNIQUE] INDEX <index-name> ON <table-name> ( <column-name> [, <column-name>]* ) | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | puts "\"[Operator \\.]\".</p>" Section {CREATE INDEX} createindex Syntax {sql-statement} { CREATE [UNIQUE] INDEX <index-name> ON <table-name> ( <column-name> [, <column-name>]* ) [ ON CONFLICT <conflict-algorithm> ] } {column-name} { <name> [ ASC | DESC ] } puts { <p>The CREATE INDEX command consists of the keywords "CREATE INDEX" followed |
︙ | ︙ | |||
278 279 280 281 282 283 284 285 286 287 288 289 290 291 | UNIQUE [ <conflict-clause> ] | CHECK ( <expr> ) [ <conflict-clause> ] | DEFAULT <value> } {constraint} { PRIMARY KEY ( <name> [, <name>]* ) [ <conflict-clause> ]| UNIQUE ( <name> [, <name>]* ) [ <conflict-clause> ] | CHECK ( <expr> ) [ <conflict-clause> ] } puts { <p>A CREATE TABLE statement is basically the keywords "CREATE TABLE" followed by the name of a new table and a parenthesized list of column definitions and constraints. The table name can be either an identifier or a string. The only reserved table name is "<b>sqlite_master</b>" which | > > | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | UNIQUE [ <conflict-clause> ] | CHECK ( <expr> ) [ <conflict-clause> ] | DEFAULT <value> } {constraint} { PRIMARY KEY ( <name> [, <name>]* ) [ <conflict-clause> ]| UNIQUE ( <name> [, <name>]* ) [ <conflict-clause> ] | CHECK ( <expr> ) [ <conflict-clause> ] } {conflict-clause} { ON CONFLICT <conflict-algorithm> } puts { <p>A CREATE TABLE statement is basically the keywords "CREATE TABLE" followed by the name of a new table and a parenthesized list of column definitions and constraints. The table name can be either an identifier or a string. The only reserved table name is "<b>sqlite_master</b>" which |
︙ | ︙ | |||
559 560 561 562 563 564 565 | "<b>count(distinct</b> <i>COLUMN-NAME</i><b>)</b>" is not. </p> } Section INSERT insert Syntax {sql-statement} { | | | | 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 | "<b>count(distinct</b> <i>COLUMN-NAME</i><b>)</b>" is not. </p> } Section INSERT insert Syntax {sql-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 { <p>The INSERT statement comes in two basic forms. The first form (with the "VALUES" keyword) creates a single new row in an existing table. If no column-list is specified then the number of values must be the same as the number of columns in the table. If a column-list |
︙ | ︙ | |||
586 587 588 589 590 591 592 | for every row of the SELECT result. The SELECT may be simple or compound. If the SELECT statement has an ORDER BY clause, 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 | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 | for every row of the SELECT result. The SELECT may be simple or compound. If the SELECT statement has an ORDER BY clause, 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. 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 Syntax {sql-statement} { SELECT <result> FROM <table-list> [WHERE <expression>] |
︙ | ︙ | |||
671 672 673 674 675 676 677 | removing the results of the right SELECT. When three are more SELECTs are connected into a compound, they group from left to right.</p> } Section UPDATE update Syntax {sql-statement} { | | | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 | removing the results of the right SELECT. When three are more SELECTs are connected into a compound, they group from left to right.</p> } Section UPDATE update Syntax {sql-statement} { UPDATE [ OR <conflict-algorithm> ] <table-name> SET <assignment> [, <assignment>] [WHERE <expression>] } {assignment} { <column-name> = <expression> } puts { |
︙ | ︙ | |||
709 710 711 712 713 714 715 | In version 1.0 of SQLite, the VACUUM command would invoke <b>gdbm_reorganize()</b> to clean up the backend database file. Beginning with version 2.0 of SQLite, GDBM is no longer used for the database backend and VACUUM has become a no-op. </p> } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 | In version 1.0 of SQLite, the VACUUM command would invoke <b>gdbm_reorganize()</b> to clean up the backend database file. Beginning with version 2.0 of SQLite, GDBM is no longer used for the database backend and VACUUM has become a no-op. </p> } puts { <p><hr /></p> <p><a href="index.html"><img src="/goback.jpg" border=0 /> Back to the SQLite Home Page</a> </p> </body></html>} |