mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Added ON CONFLICT support to COPY. Updates to documentation. Bug fixes. (CVS 359)
FossilOrigin-Name: cf1538d71c9ce12d5e59f367e03642cbcaf6b717
This commit is contained in:
@@ -343,6 +343,9 @@ faq.html: $(TOP)/www/faq.tcl
|
|||||||
formatchng.html: $(TOP)/www/formatchng.tcl
|
formatchng.html: $(TOP)/www/formatchng.tcl
|
||||||
tclsh $(TOP)/www/formatchng.tcl >formatchng.html
|
tclsh $(TOP)/www/formatchng.tcl >formatchng.html
|
||||||
|
|
||||||
|
conflict.html: $(TOP)/www/conflict.tcl
|
||||||
|
tclsh $(TOP)/www/conflict.tcl >conflict.html
|
||||||
|
|
||||||
download.html: $(TOP)/www/download.tcl
|
download.html: $(TOP)/www/download.tcl
|
||||||
tclsh $(TOP)/www/download.tcl >download.html
|
tclsh $(TOP)/www/download.tcl >download.html
|
||||||
|
|
||||||
@@ -365,7 +368,8 @@ DOC = \
|
|||||||
download.html \
|
download.html \
|
||||||
speed.html \
|
speed.html \
|
||||||
faq.html \
|
faq.html \
|
||||||
formatchng.html
|
formatchng.html \
|
||||||
|
conflict.html
|
||||||
|
|
||||||
doc: $(DOC)
|
doc: $(DOC)
|
||||||
mkdir -p doc
|
mkdir -p doc
|
||||||
|
35
manifest
35
manifest
@@ -1,7 +1,7 @@
|
|||||||
C Better\stesting\sof\sthe\sON\sCONFLICT\slogic.\s(CVS\s358)
|
C Added\sON\sCONFLICT\ssupport\sto\sCOPY.\sUpdates\sto\sdocumentation.\sBug\sfixes.\s(CVS\s359)
|
||||||
D 2002-01-30T04:32:01
|
D 2002-01-30T16:17:24
|
||||||
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
|
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
|
||||||
F Makefile.template 3e26a3b9e7aee1b811deaf673e8d8973bdb3f22d
|
F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
|
||||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||||
F VERSION 34f7c904a063d2d3791c38521e40ae1648cd2e7e
|
F VERSION 34f7c904a063d2d3791c38521e40ae1648cd2e7e
|
||||||
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
|
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
|
||||||
@@ -21,35 +21,35 @@ F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
|
|||||||
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
||||||
F src/btree.c c796e387da340cb628dc1e41f684fc20253f561e
|
F src/btree.c c796e387da340cb628dc1e41f684fc20253f561e
|
||||||
F src/btree.h 9ead7f54c270d8a554e59352ca7318fdaf411390
|
F src/btree.h 9ead7f54c270d8a554e59352ca7318fdaf411390
|
||||||
F src/build.c c55881f270b1a77d1025dcfba7c87db46d43a9d0
|
F src/build.c 78571589a39d4b03b19b1300db8b23f1d3e1bab2
|
||||||
F src/delete.c 4cdb6d2e94e2eb1b1aa79eefafd4669d43c249d6
|
F src/delete.c 4cdb6d2e94e2eb1b1aa79eefafd4669d43c249d6
|
||||||
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 5de9d85889d4b97c823be1b9ebf01c30e29947b3
|
F src/insert.c 37971598f1cbfc9de9bd1d269529e233003652b8
|
||||||
F src/main.c 0205771a6c31a9858ff131fc1e797b589afb76bf
|
F src/main.c 0205771a6c31a9858ff131fc1e797b589afb76bf
|
||||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||||
F src/os.c c615faa4d23e742e0650e0751a6ad2a18438ad53
|
F src/os.c c615faa4d23e742e0650e0751a6ad2a18438ad53
|
||||||
F src/os.h 5405a5695bf16889d4fc6caf9d42043caa41c269
|
F src/os.h 5405a5695bf16889d4fc6caf9d42043caa41c269
|
||||||
F src/pager.c 1e80a3ba731e454df6bd2e58d32eeba7dd65121b
|
F src/pager.c 1e80a3ba731e454df6bd2e58d32eeba7dd65121b
|
||||||
F src/pager.h f78d064c780855ff70beacbeba0e2324471b26fe
|
F src/pager.h f78d064c780855ff70beacbeba0e2324471b26fe
|
||||||
F src/parse.y fd79a09265b4703e37a62084db6fe67c834defb4
|
F src/parse.y e80f1cf6a280e3da0f49c9b60b14edc2f15912ec
|
||||||
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
|
||||||
F src/shell.c c102dfe388c7618a668c944ff157c49cb48f28e3
|
F src/shell.c c102dfe388c7618a668c944ff157c49cb48f28e3
|
||||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||||
F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c
|
F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c
|
||||||
F src/sqliteInt.h 60c0945eb4159c44adec9aadadb61dfd931d29e9
|
F src/sqliteInt.h 3bf0938d01e1cc57154c39c730d7e91d9bd60359
|
||||||
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
|
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
|
||||||
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
|
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
|
||||||
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
|
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
|
||||||
F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
|
F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
|
||||||
F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b
|
F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b
|
||||||
F src/tokenize.c 1199b96a82d5c41509b5e24fc9faa1852b7f3135
|
F src/tokenize.c 1199b96a82d5c41509b5e24fc9faa1852b7f3135
|
||||||
F src/update.c 5ffd4bbd380f1fa99da184f28416e6dcf8b5508e
|
F src/update.c c6215079d7604fd1cf785eff64ec0e03e97bd138
|
||||||
F src/util.c 8f8973dd55a6ec63be9632fc5de86965c99d6327
|
F src/util.c 8f8973dd55a6ec63be9632fc5de86965c99d6327
|
||||||
F src/vdbe.c 893fa634870a5ea67c30ba61b7881b537f5c2723
|
F src/vdbe.c 14667d889d9d9ebdc5f5f5d030312071f41b7873
|
||||||
F src/vdbe.h 5b1bd518126fc5a30e6ea13fe11de931b32c4b59
|
F src/vdbe.h 5b1bd518126fc5a30e6ea13fe11de931b32c4b59
|
||||||
F src/where.c 2dda39367f193194e4c7d2e0dcab31527d9d8aba
|
F src/where.c 2dda39367f193194e4c7d2e0dcab31527d9d8aba
|
||||||
F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
|
F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
|
||||||
@@ -57,8 +57,8 @@ 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 66ac8bec8e25224b6aca18d76dd40b0afa27e227
|
F test/conflict.test 685725a37ec13e671ec57f48285c1c08bba21c99
|
||||||
F test/copy.test 768e6f1701a07d08090e1ca7f7dcce0a7a72b43e
|
F test/copy.test 4079990fb84be696d29c43de9fa6492312f165f0
|
||||||
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
|
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
|
||||||
F test/expr.test c8a495050dcec3f9e68538c3ef466726933302c1
|
F test/expr.test c8a495050dcec3f9e68538c3ef466726933302c1
|
||||||
F test/func.test 51dbe3f8a4c28972751697423e6acc5d6b551df1
|
F test/func.test 51dbe3f8a4c28972751697423e6acc5d6b551df1
|
||||||
@@ -107,21 +107,22 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
|
|||||||
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
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 6b802e152436c7596308b6a4901e91415be0d9d4
|
F www/changes.tcl 3770ded78faa7a634b55fbf5316caa4cb150e5f9
|
||||||
|
F www/conflict.tcl 3f70c01680b8d763bf3305eb67f6d85fdf83b497
|
||||||
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
||||||
F www/download.tcl 1ea61f9d89a2a5a9b2cee36b0d5cf97321bdefe0
|
F www/download.tcl 1ea61f9d89a2a5a9b2cee36b0d5cf97321bdefe0
|
||||||
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
||||||
F www/faq.tcl 32cbc134879871604070d4cc3a32e73fb22a35f9
|
F www/faq.tcl 32cbc134879871604070d4cc3a32e73fb22a35f9
|
||||||
F www/formatchng.tcl d96e5e937dcbbebd481720aa08745ca5a906a63f
|
F www/formatchng.tcl 2d9a35c787823b48d72a5c64bb5414a43e26d5ad
|
||||||
F www/index.tcl 748614d8208c761ed3840e7958b8eed04de81822
|
F www/index.tcl 748614d8208c761ed3840e7958b8eed04de81822
|
||||||
F www/lang.tcl 6843fd3f85cba95fd199a350533ce742c706603c
|
F www/lang.tcl f04d74017e627f6f133438234bd20fbe585ca4cf
|
||||||
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 8229b5f6a348a56432a4a609ee125520c5831973
|
P 9bbddb8e013b47547164f71f2d7abd995f8d7385
|
||||||
R 6092c649bf38d0cb57a1ec35caeb9370
|
R ad077c176de250ed6687e2b5636281f6
|
||||||
U drh
|
U drh
|
||||||
Z 733d233a561b4a44b1706a6a61fc3f4e
|
Z 1ba7e7bec405961a534e04fc39ece2b3
|
||||||
|
@@ -1 +1 @@
|
|||||||
9bbddb8e013b47547164f71f2d7abd995f8d7385
|
cf1538d71c9ce12d5e59f367e03642cbcaf6b717
|
32
src/build.c
32
src/build.c
@@ -25,7 +25,7 @@
|
|||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
** PRAGMA
|
** PRAGMA
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.68 2002/01/29 23:07:02 drh Exp $
|
** $Id: build.c,v 1.69 2002/01/30 16:17:24 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -1332,7 +1332,8 @@ void sqliteCopy(
|
|||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
Token *pTableName, /* The name of the table into which we will insert */
|
Token *pTableName, /* The name of the table into which we will insert */
|
||||||
Token *pFilename, /* The file from which to obtain information */
|
Token *pFilename, /* The file from which to obtain information */
|
||||||
Token *pDelimiter /* Use this as the field delimiter */
|
Token *pDelimiter, /* Use this as the field delimiter */
|
||||||
|
int onError /* What to do if a constraint fails */
|
||||||
){
|
){
|
||||||
Table *pTab;
|
Table *pTab;
|
||||||
char *zTab;
|
char *zTab;
|
||||||
@@ -1376,6 +1377,9 @@ void sqliteCopy(
|
|||||||
sqliteVdbeAddOp(v, openOp, i, pIdx->tnum);
|
sqliteVdbeAddOp(v, openOp, i, pIdx->tnum);
|
||||||
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
|
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
|
||||||
}
|
}
|
||||||
|
if( db->flags & SQLITE_CountRows ){
|
||||||
|
sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */
|
||||||
|
}
|
||||||
end = sqliteVdbeMakeLabel(v);
|
end = sqliteVdbeMakeLabel(v);
|
||||||
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end);
|
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end);
|
||||||
if( pDelimiter ){
|
if( pDelimiter ){
|
||||||
@@ -1390,9 +1394,6 @@ void sqliteCopy(
|
|||||||
}else{
|
}else{
|
||||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
|
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
|
||||||
}
|
}
|
||||||
if( pTab->pIndex ){
|
|
||||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
|
||||||
}
|
|
||||||
for(i=0; i<pTab->nCol; i++){
|
for(i=0; i<pTab->nCol; i++){
|
||||||
if( i==pTab->iPKey ){
|
if( i==pTab->iPKey ){
|
||||||
/* The integer primary key column is filled with NULL since its
|
/* The integer primary key column is filled with NULL since its
|
||||||
@@ -1402,17 +1403,10 @@ void sqliteCopy(
|
|||||||
sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
|
sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, 0, 0, onError, addr);
|
||||||
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
|
sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0);
|
||||||
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
if( (db->flags & SQLITE_CountRows)!=0 ){
|
||||||
if( pIdx->pNext ){
|
sqliteVdbeAddOp(v, OP_AddImm, 1, 0); /* Increment row count */
|
||||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
|
||||||
}
|
|
||||||
for(j=0; j<pIdx->nColumn; j++){
|
|
||||||
sqliteVdbeAddOp(v, OP_FileColumn, pIdx->aiColumn[j], 0);
|
|
||||||
}
|
|
||||||
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
|
|
||||||
sqliteVdbeAddOp(v, OP_IdxPut, i, pIdx->onError!=OE_None);
|
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
|
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
|
||||||
sqliteVdbeResolveLabel(v, end);
|
sqliteVdbeResolveLabel(v, end);
|
||||||
@@ -1420,6 +1414,12 @@ void sqliteCopy(
|
|||||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0);
|
sqliteVdbeAddOp(v, OP_Commit, 0, 0);
|
||||||
}
|
}
|
||||||
|
if( db->flags & SQLITE_CountRows ){
|
||||||
|
sqliteVdbeAddOp(v, OP_ColumnCount, 1, 0);
|
||||||
|
sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
|
||||||
|
sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
|
||||||
|
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_cleanup:
|
copy_cleanup:
|
||||||
|
50
src/insert.c
50
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.37 2002/01/30 04:32:01 drh Exp $
|
** $Id: insert.c,v 1.38 2002/01/30 16:17:24 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -202,9 +202,7 @@ void sqliteInsert(
|
|||||||
/* Push the record number for the new entry onto the stack. The
|
/* Push the record number for the new entry onto the stack. The
|
||||||
** record number is a randomly generate integer created by NewRecno
|
** record number is a randomly generate integer created by NewRecno
|
||||||
** except when the table has an INTEGER PRIMARY KEY column, in which
|
** except when the table has an INTEGER PRIMARY KEY column, in which
|
||||||
** case the record number is the same as that column. May a copy
|
** case the record number is the same as that column.
|
||||||
** because sqliteGenerateConstraintChecks() requires two copies of
|
|
||||||
** the record number.
|
|
||||||
*/
|
*/
|
||||||
if( keyColumn>=0 ){
|
if( keyColumn>=0 ){
|
||||||
if( srcTab>=0 ){
|
if( srcTab>=0 ){
|
||||||
@@ -216,7 +214,6 @@ void sqliteInsert(
|
|||||||
}else{
|
}else{
|
||||||
sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
|
sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
|
||||||
|
|
||||||
/* Push onto the stack, data for all columns of the new entry, beginning
|
/* Push onto the stack, data for all columns of the new entry, beginning
|
||||||
** with the first column.
|
** with the first column.
|
||||||
@@ -251,8 +248,8 @@ void sqliteInsert(
|
|||||||
** do the insertion.
|
** do the insertion.
|
||||||
*/
|
*/
|
||||||
endOfLoop = sqliteVdbeMakeLabel(v);
|
endOfLoop = sqliteVdbeMakeLabel(v);
|
||||||
sqliteGenerateConstraintChecks(pParse, pTab, base, 0,1,onError,endOfLoop,0);
|
sqliteGenerateConstraintChecks(pParse, pTab, base, 0,0,0, onError, endOfLoop);
|
||||||
sqliteCompleteInsertion(pParse, pTab, base, 0, 1);
|
sqliteCompleteInsertion(pParse, pTab, base, 0,0,0);
|
||||||
|
|
||||||
/* If inserting from a SELECT, keep a count of the number of
|
/* If inserting from a SELECT, keep a count of the number of
|
||||||
** rows inserted.
|
** rows inserted.
|
||||||
@@ -302,11 +299,11 @@ insert_cleanup:
|
|||||||
** When this routine is called, the stack contains (from bottom to top)
|
** When this routine is called, the stack contains (from bottom to top)
|
||||||
** the following values:
|
** the following values:
|
||||||
**
|
**
|
||||||
** 1. The recno of the row to be updated before it is updated.
|
** 1. The recno of the row to be updated before it is updated. This
|
||||||
|
** value is omitted unless we are doing an UPDATE that involves a
|
||||||
|
** change to the record number.
|
||||||
**
|
**
|
||||||
** 2. The recno of the row after the update. (This is usually the
|
** 2. The recno of the row after the update.
|
||||||
** same as (1) but can be different if an UPDATE changes an
|
|
||||||
** INTEGER PRIMARY KEY column.)
|
|
||||||
**
|
**
|
||||||
** 3. The data in the first column of the entry after the update.
|
** 3. The data in the first column of the entry after the update.
|
||||||
**
|
**
|
||||||
@@ -314,9 +311,9 @@ insert_cleanup:
|
|||||||
**
|
**
|
||||||
** N. The data in the last column of the entry after the update.
|
** N. The data in the last column of the entry after the update.
|
||||||
**
|
**
|
||||||
** The old recno shown as entry (1) above is omitted if the recnoChng
|
** The old recno shown as entry (1) above is omitted unless both isUpdate
|
||||||
** parameter is 0. recnoChange is true if the record number is changing
|
** and recnoChng are both 1. isUpdate is true for UPDATEs and false for
|
||||||
** and false if not.
|
** INSERTs and recnoChng is ture if the record number is being changed.
|
||||||
**
|
**
|
||||||
** The code generated by this routine pushes additional entries onto
|
** The code generated by this routine pushes additional entries onto
|
||||||
** the stack which are the keys for new index entries for the new record.
|
** the stack which are the keys for new index entries for the new record.
|
||||||
@@ -373,9 +370,9 @@ void sqliteGenerateConstraintChecks(
|
|||||||
int base, /* Index of a read/write cursor pointing at pTab */
|
int base, /* Index of a read/write cursor pointing at pTab */
|
||||||
char *aIdxUsed, /* Which indices are used. NULL means all are used */
|
char *aIdxUsed, /* Which indices are used. NULL means all are used */
|
||||||
int recnoChng, /* True if the record number will change */
|
int recnoChng, /* True if the record number will change */
|
||||||
|
int isUpdate, /* True for UPDATE, False for INSERT */
|
||||||
int overrideError, /* Override onError to this if not OE_Default */
|
int overrideError, /* Override onError to this if not OE_Default */
|
||||||
int ignoreDest, /* Jump to this label on an OE_Ignore resolution */
|
int ignoreDest /* Jump to this label on an OE_Ignore resolution */
|
||||||
int isUpdate /* True for UPDATE, False for INSERT */
|
|
||||||
){
|
){
|
||||||
int i;
|
int i;
|
||||||
Vdbe *v;
|
Vdbe *v;
|
||||||
@@ -388,11 +385,11 @@ void sqliteGenerateConstraintChecks(
|
|||||||
int seenReplace = 0;
|
int seenReplace = 0;
|
||||||
int jumpInst;
|
int jumpInst;
|
||||||
int contAddr;
|
int contAddr;
|
||||||
|
int hasTwoRecnos = (isUpdate && recnoChng);
|
||||||
|
|
||||||
v = sqliteGetVdbe(pParse);
|
v = sqliteGetVdbe(pParse);
|
||||||
assert( v!=0 );
|
assert( v!=0 );
|
||||||
nCol = pTab->nCol;
|
nCol = pTab->nCol;
|
||||||
recnoChng = (recnoChng!=0); /* Must be either 1 or 0 */
|
|
||||||
|
|
||||||
/* Test all NOT NULL constraints.
|
/* Test all NOT NULL constraints.
|
||||||
*/
|
*/
|
||||||
@@ -417,7 +414,7 @@ void sqliteGenerateConstraintChecks(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OE_Ignore: {
|
case OE_Ignore: {
|
||||||
sqliteVdbeAddOp(v, OP_Pop, nCol+1+recnoChng, 0);
|
sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -437,7 +434,7 @@ void sqliteGenerateConstraintChecks(
|
|||||||
|
|
||||||
/* Test all UNIQUE constraints. Add index records as we go.
|
/* Test all UNIQUE constraints. Add index records as we go.
|
||||||
*/
|
*/
|
||||||
if( recnoChng && pTab->iPKey>=0 && pTab->keyConf!=OE_Replace
|
if( (recnoChng || !isUpdate) && pTab->iPKey>=0 && pTab->keyConf!=OE_Replace
|
||||||
&& overrideError!=OE_Replace ){
|
&& overrideError!=OE_Replace ){
|
||||||
sqliteVdbeAddOp(v, OP_Dup, nCol, 1);
|
sqliteVdbeAddOp(v, OP_Dup, nCol, 1);
|
||||||
jumpInst = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
|
jumpInst = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
|
||||||
@@ -451,7 +448,7 @@ void sqliteGenerateConstraintChecks(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OE_Ignore: {
|
case OE_Ignore: {
|
||||||
sqliteVdbeAddOp(v, OP_Pop, nCol+2, 0);
|
sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -483,7 +480,7 @@ void sqliteGenerateConstraintChecks(
|
|||||||
if( overrideError!=OE_Default ){
|
if( overrideError!=OE_Default ){
|
||||||
onError = overrideError;
|
onError = overrideError;
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+recnoChng, 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);
|
||||||
switch( onError ){
|
switch( onError ){
|
||||||
case OE_Abort: {
|
case OE_Abort: {
|
||||||
@@ -492,14 +489,14 @@ void sqliteGenerateConstraintChecks(
|
|||||||
}
|
}
|
||||||
case OE_Ignore: {
|
case OE_Ignore: {
|
||||||
assert( seenReplace==0 );
|
assert( seenReplace==0 );
|
||||||
sqliteVdbeAddOp(v, OP_Pop, nCol+extra+2+recnoChng, 0);
|
sqliteVdbeAddOp(v, OP_Pop, nCol+extra+2+hasTwoRecnos, 0);
|
||||||
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OE_Replace: {
|
case OE_Replace: {
|
||||||
sqliteGenerateRowDelete(v, pTab, base);
|
sqliteGenerateRowDelete(v, pTab, base);
|
||||||
if( isUpdate ){
|
if( isUpdate ){
|
||||||
sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+recnoChng, 1);
|
sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1);
|
||||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||||
}
|
}
|
||||||
seenReplace = 1;
|
seenReplace = 1;
|
||||||
@@ -519,7 +516,7 @@ void sqliteGenerateConstraintChecks(
|
|||||||
** and the recno for the new entry. This routine creates the new
|
** and the recno for the new entry. This routine creates the new
|
||||||
** entries in all indices and in the main table.
|
** entries in all indices and in the main table.
|
||||||
**
|
**
|
||||||
** The arguments to this routine should be the same as the first five
|
** The arguments to this routine should be the same as the first six
|
||||||
** arguments to sqliteGenerateConstraintChecks.
|
** arguments to sqliteGenerateConstraintChecks.
|
||||||
*/
|
*/
|
||||||
void sqliteCompleteInsertion(
|
void sqliteCompleteInsertion(
|
||||||
@@ -527,7 +524,8 @@ void sqliteCompleteInsertion(
|
|||||||
Table *pTab, /* the table into which we are inserting */
|
Table *pTab, /* the table into which we are inserting */
|
||||||
int base, /* Index of a read/write cursor pointing at pTab */
|
int base, /* Index of a read/write cursor pointing at pTab */
|
||||||
char *aIdxUsed, /* Which indices are used. NULL means all are used */
|
char *aIdxUsed, /* Which indices are used. NULL means all are used */
|
||||||
int recnoChng /* True if the record number changed */
|
int recnoChng, /* True if the record number will change */
|
||||||
|
int isUpdate /* True for UPDATE, False for INSERT */
|
||||||
){
|
){
|
||||||
int i;
|
int i;
|
||||||
Vdbe *v;
|
Vdbe *v;
|
||||||
@@ -543,7 +541,7 @@ void sqliteCompleteInsertion(
|
|||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||||
sqliteVdbeAddOp(v, OP_PutIntKey, base, 0);
|
sqliteVdbeAddOp(v, OP_PutIntKey, base, 0);
|
||||||
if( recnoChng ){
|
if( isUpdate && recnoChng ){
|
||||||
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
|
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
src/parse.y
10
src/parse.y
@@ -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.43 2002/01/29 18:41:25 drh Exp $
|
** @(#) $Id: parse.y,v 1.44 2002/01/30 16:17:24 drh Exp $
|
||||||
*/
|
*/
|
||||||
%token_prefix TK_
|
%token_prefix TK_
|
||||||
%token_type {Token}
|
%token_type {Token}
|
||||||
@@ -548,10 +548,10 @@ cmd ::= DROP INDEX ids(X). {sqliteDropIndex(pParse, &X);}
|
|||||||
|
|
||||||
///////////////////////////// The COPY command ///////////////////////////////
|
///////////////////////////// The COPY command ///////////////////////////////
|
||||||
//
|
//
|
||||||
cmd ::= COPY ids(X) FROM ids(Y) USING DELIMITERS STRING(Z).
|
cmd ::= COPY onconf_u(R) ids(X) FROM ids(Y) USING DELIMITERS STRING(Z).
|
||||||
{sqliteCopy(pParse,&X,&Y,&Z);}
|
{sqliteCopy(pParse,&X,&Y,&Z,R);}
|
||||||
cmd ::= COPY ids(X) FROM ids(Y).
|
cmd ::= COPY onconf_u(R) ids(X) FROM ids(Y).
|
||||||
{sqliteCopy(pParse,&X,&Y,0);}
|
{sqliteCopy(pParse,&X,&Y,0,R);}
|
||||||
|
|
||||||
///////////////////////////// The VACUUM command /////////////////////////////
|
///////////////////////////// The VACUUM command /////////////////////////////
|
||||||
//
|
//
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.81 2002/01/29 23:07:02 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.82 2002/01/30 16:17:24 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
@@ -527,7 +527,7 @@ void sqliteExprIfFalse(Parse*, Expr*, int);
|
|||||||
Table *sqliteFindTable(sqlite*,char*);
|
Table *sqliteFindTable(sqlite*,char*);
|
||||||
Index *sqliteFindIndex(sqlite*,char*);
|
Index *sqliteFindIndex(sqlite*,char*);
|
||||||
void sqliteUnlinkAndDeleteIndex(sqlite*,Index*);
|
void sqliteUnlinkAndDeleteIndex(sqlite*,Index*);
|
||||||
void sqliteCopy(Parse*, Token*, Token*, Token*);
|
void sqliteCopy(Parse*, Token*, Token*, Token*, int);
|
||||||
void sqliteVacuum(Parse*, Token*);
|
void sqliteVacuum(Parse*, Token*);
|
||||||
int sqliteGlobCompare(const unsigned char*,const unsigned char*);
|
int sqliteGlobCompare(const unsigned char*,const unsigned char*);
|
||||||
int sqliteLikeCompare(const unsigned char*,const unsigned char*);
|
int sqliteLikeCompare(const unsigned char*,const unsigned char*);
|
||||||
@@ -550,4 +550,4 @@ int sqliteExprIsConstant(Expr*);
|
|||||||
void sqliteGenerateRowDelete(Vdbe*, Table*, int);
|
void sqliteGenerateRowDelete(Vdbe*, Table*, int);
|
||||||
void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*);
|
void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*);
|
||||||
void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
|
void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
|
||||||
void sqliteCompleteInsertion(Parse*, Table*, int, char*, int);
|
void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int);
|
||||||
|
@@ -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 UPDATE statements.
|
** to handle UPDATE statements.
|
||||||
**
|
**
|
||||||
** $Id: update.c,v 1.30 2002/01/29 23:07:02 drh Exp $
|
** $Id: update.c,v 1.31 2002/01/30 16:17:24 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -253,8 +253,8 @@ void sqliteUpdate(
|
|||||||
|
|
||||||
/* Do constraint checks
|
/* Do constraint checks
|
||||||
*/
|
*/
|
||||||
sqliteGenerateConstraintChecks(pParse, pTab, base, aIdxUsed, chngRecno,
|
sqliteGenerateConstraintChecks(pParse, pTab, base, aIdxUsed, chngRecno, 1,
|
||||||
onError, addr,1);
|
onError, addr);
|
||||||
|
|
||||||
/* Delete the old indices for the current record.
|
/* Delete the old indices for the current record.
|
||||||
*/
|
*/
|
||||||
@@ -268,7 +268,7 @@ void sqliteUpdate(
|
|||||||
|
|
||||||
/* Create the new index entries and the new record.
|
/* Create the new index entries and the new record.
|
||||||
*/
|
*/
|
||||||
sqliteCompleteInsertion(pParse, pTab, base, aIdxUsed, chngRecno);
|
sqliteCompleteInsertion(pParse, pTab, base, aIdxUsed, chngRecno, 1);
|
||||||
|
|
||||||
/* Increment the row counter
|
/* Increment the row counter
|
||||||
*/
|
*/
|
||||||
|
38
src/vdbe.c
38
src/vdbe.c
@@ -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.111 2002/01/30 00:54:56 drh Exp $
|
** $Id: vdbe.c,v 1.112 2002/01/30 16:17:24 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -3824,8 +3824,11 @@ case OP_FileOpen: {
|
|||||||
** we are able to get another line, split the line apart using P3 as
|
** we are able to get another line, split the line apart using P3 as
|
||||||
** a delimiter. There should be P1 fields. If the input line contains
|
** a delimiter. There should be P1 fields. If the input line contains
|
||||||
** more than P1 fields, ignore the excess. If the input line contains
|
** more than P1 fields, ignore the excess. If the input line contains
|
||||||
** fewer than P1 fields, assume the remaining fields contain an
|
** fewer than P1 fields, assume the remaining fields contain NULLs.
|
||||||
** empty strings.
|
**
|
||||||
|
** Input ends if a line consists of just "\.". A field containing only
|
||||||
|
** "\N" is a null field. The backslash \ character can be used be used
|
||||||
|
** to escape newlines or the delimiter.
|
||||||
*/
|
*/
|
||||||
case OP_FileRead: {
|
case OP_FileRead: {
|
||||||
int n, eol, nField, i, c, nDelim;
|
int n, eol, nField, i, c, nDelim;
|
||||||
@@ -3858,11 +3861,18 @@ case OP_FileRead: {
|
|||||||
eol = 1;
|
eol = 1;
|
||||||
p->zLine[n] = 0;
|
p->zLine[n] = 0;
|
||||||
}else{
|
}else{
|
||||||
while( p->zLine[n] ){ n++; }
|
int c;
|
||||||
if( n>0 && p->zLine[n-1]=='\n' ){
|
while( (c = p->zLine[n])!=0 ){
|
||||||
n--;
|
if( c=='\\' ){
|
||||||
|
if( p->zLine[n+1]==0 ) break;
|
||||||
|
n += 2;
|
||||||
|
}else if( c=='\n' ){
|
||||||
p->zLine[n] = 0;
|
p->zLine[n] = 0;
|
||||||
eol = 1;
|
eol = 1;
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
n++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3879,6 +3889,13 @@ case OP_FileRead: {
|
|||||||
for(i=1; *z!=0 && i<=nField; i++){
|
for(i=1; *z!=0 && i<=nField; i++){
|
||||||
int from, to;
|
int from, to;
|
||||||
from = to = 0;
|
from = to = 0;
|
||||||
|
if( z[0]=='\\' && z[1]=='N'
|
||||||
|
&& (z[2]==0 || strncmp(&z[2],zDelim,nDelim)==0) ){
|
||||||
|
if( i<=nField ) p->azField[i-1] = 0;
|
||||||
|
z += 2 + nDelim;
|
||||||
|
if( i<nField ) p->azField[i] = z;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
while( z[from] ){
|
while( z[from] ){
|
||||||
if( z[from]=='\\' && z[from+1]!=0 ){
|
if( z[from]=='\\' && z[from+1]!=0 ){
|
||||||
z[to++] = z[from+1];
|
z[to++] = z[from+1];
|
||||||
@@ -3898,7 +3915,7 @@ case OP_FileRead: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while( i<nField ){
|
while( i<nField ){
|
||||||
p->azField[i++] = "";
|
p->azField[i++] = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -3923,11 +3940,16 @@ case OP_FileColumn: {
|
|||||||
}else{
|
}else{
|
||||||
z = 0;
|
z = 0;
|
||||||
}
|
}
|
||||||
if( z==0 ) z = "";
|
|
||||||
p->tos++;
|
p->tos++;
|
||||||
|
if( z ){
|
||||||
aStack[p->tos].n = strlen(z) + 1;
|
aStack[p->tos].n = strlen(z) + 1;
|
||||||
zStack[p->tos] = z;
|
zStack[p->tos] = z;
|
||||||
aStack[p->tos].flags = STK_Str;
|
aStack[p->tos].flags = STK_Str;
|
||||||
|
}else{
|
||||||
|
aStack[p->tos].n = 0;
|
||||||
|
zStack[p->tos] = 0;
|
||||||
|
aStack[p->tos].flags = STK_Null;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
# 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.2 2002/01/30 04:32:01 drh Exp $
|
# $Id: conflict.test,v 1.3 2002/01/30 16:17:25 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing the COPY statement.
|
# focus of this file is testing the COPY statement.
|
||||||
#
|
#
|
||||||
# $Id: copy.test,v 1.6 2001/09/16 00:13:28 drh Exp $
|
# $Id: copy.test,v 1.7 2002/01/30 16:17:25 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -123,6 +123,7 @@ do_test copy-2.1 {
|
|||||||
execsql {COPY test2 FROM 'data21.txt'}
|
execsql {COPY test2 FROM 'data21.txt'}
|
||||||
execsql {SELECT x from test2}
|
execsql {SELECT x from test2}
|
||||||
} $x
|
} $x
|
||||||
|
file delete -force data21.txt
|
||||||
|
|
||||||
# Test the escape character mechanism
|
# Test the escape character mechanism
|
||||||
#
|
#
|
||||||
@@ -137,9 +138,79 @@ do_test copy-3.1 {
|
|||||||
SELECT * FROM t1 ORDER BY a;
|
SELECT * FROM t1 ORDER BY a;
|
||||||
}
|
}
|
||||||
} {hello {world 2} {hello world} 1}
|
} {hello {world 2} {hello world} 1}
|
||||||
|
do_test copy-3.2 {
|
||||||
|
set fd [open data6.txt w]
|
||||||
|
puts $fd "1\thello\\\nworld"
|
||||||
|
puts $fd "2\thello world"
|
||||||
|
close $fd
|
||||||
|
execsql {
|
||||||
|
DELETE FROM t1;
|
||||||
|
COPY t1 FROM 'data6.txt';
|
||||||
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
}
|
||||||
|
} {1 {hello
|
||||||
|
world} 2 {hello world}}
|
||||||
|
|
||||||
|
# Test the embedded NULL logic.
|
||||||
|
#
|
||||||
|
do_test copy-4.1 {
|
||||||
|
set fd [open data6.txt w]
|
||||||
|
puts $fd "1\t\\N"
|
||||||
|
puts $fd "\\N\thello world"
|
||||||
|
close $fd
|
||||||
|
execsql {
|
||||||
|
DELETE FROM t1;
|
||||||
|
COPY t1 FROM 'data6.txt';
|
||||||
|
SELECT * FROM t1 WHERE a IS NULL;
|
||||||
|
}
|
||||||
|
} {{} {hello world}}
|
||||||
|
do_test copy-4.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM t1 WHERE b IS NULL;
|
||||||
|
}
|
||||||
|
} {1 {}}
|
||||||
|
|
||||||
|
# Test the conflict resolution logic for COPY
|
||||||
|
#
|
||||||
|
do_test copy-5.1 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE t1;
|
||||||
|
CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE, c);
|
||||||
|
COPY t1 FROM 'data5.txt' USING DELIMITERS '|';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
} {11 22 33 22 33 11}
|
||||||
|
do_test copy-5.2 {
|
||||||
|
set fd [open data6.txt w]
|
||||||
|
puts $fd "33|22|44"
|
||||||
|
close $fd
|
||||||
|
catchsql {
|
||||||
|
COPY t1 FROM 'data6.txt' USING DELIMITERS '|';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
} {1 {constraint failed}}
|
||||||
|
do_test copy-5.3 {
|
||||||
|
set fd [open data6.txt w]
|
||||||
|
puts $fd "33|22|44"
|
||||||
|
close $fd
|
||||||
|
catchsql {
|
||||||
|
COPY ON CONFLICT IGNORE t1 FROM 'data6.txt' USING DELIMITERS '|';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
} {0 {11 22 33 22 33 11}}
|
||||||
|
do_test copy-5.4 {
|
||||||
|
set fd [open data6.txt w]
|
||||||
|
puts $fd "33|22|44"
|
||||||
|
close $fd
|
||||||
|
catchsql {
|
||||||
|
COPY ON CONFLICT REPLACE t1 FROM 'data6.txt' USING DELIMITERS '|';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
} {0 {22 33 11 33 22 44}}
|
||||||
|
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
#
|
#
|
||||||
file delete -force data1.txt data2.txt data3.txt data4.txt data5.txt data21.txt
|
file delete -force data1.txt data2.txt data3.txt data4.txt data5.txt data6.txt
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
@@ -17,6 +17,15 @@ proc chng {date desc} {
|
|||||||
puts "<DD><P><UL>$desc</UL></P></DD>"
|
puts "<DD><P><UL>$desc</UL></P></DD>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chng {2002 Jan 30 (2.3.0 beta)} {
|
||||||
|
<li>Added the ability to resolve constraint conflicts is ways other than
|
||||||
|
an abort and rollback. See the documentation on the "ON CONFLICT"
|
||||||
|
clause for details.</li>
|
||||||
|
<li>NOT NULL constraints are honored.</li>
|
||||||
|
<li>The COPY command puts NULLs in columns whose data is '\N'.</li>
|
||||||
|
<li>In the COPY command, backslash can now be used to escape a newline.</li>
|
||||||
|
}
|
||||||
|
|
||||||
chng {2002 Jan 28 (2.2.5)} {
|
chng {2002 Jan 28 (2.2.5)} {
|
||||||
<li>Important bug fix: the IN operator was not working if either the
|
<li>Important bug fix: the IN operator was not working if either the
|
||||||
left-hand or right-hand side was derived from an INTEGER PRIMARY KEY.</li>
|
left-hand or right-hand side was derived from an INTEGER PRIMARY KEY.</li>
|
||||||
|
191
www/conflict.tcl
Normal file
191
www/conflict.tcl
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
#
|
||||||
|
# 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 $ }
|
||||||
|
|
||||||
|
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 and rolls back the current transaction.
|
||||||
|
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>
|
||||||
|
The default conflict resolution algorithm is to abort the
|
||||||
|
operation in progress, rollback all changes, and cancel the
|
||||||
|
current transaction. Call this algorithm "ABORT". Abort
|
||||||
|
is the standard way of dealing with a constraint error
|
||||||
|
in most SQL databases.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Sometimes ABORT is not the most helpful way of dealing
|
||||||
|
with constraint violations. Suppose, for example, you are
|
||||||
|
inserting 1000 records into a database, all within a single
|
||||||
|
transaction, but one of those records is malformed and causes
|
||||||
|
a constraint error. With the default ABORT behavior, none
|
||||||
|
of the 1000 records gets inserted. But sometimes it is
|
||||||
|
desirable to just omit the single malformed insert and
|
||||||
|
finish the other 999.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<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 {
|
||||||
|
<p><hr /></p>
|
||||||
|
<p><a href="index.html"><img src="/goback.jpg" border=0 />
|
||||||
|
Back to the SQLite Home Page</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body></html>}
|
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this Tcl script to generate the formatchng.html file.
|
# Run this Tcl script to generate the formatchng.html file.
|
||||||
#
|
#
|
||||||
set rcsid {$Id: formatchng.tcl,v 1.1 2001/12/22 19:27:41 drh Exp $ }
|
set rcsid {$Id: formatchng.tcl,v 1.2 2002/01/30 16:17:25 drh Exp $ }
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -81,6 +81,16 @@ occurred since version 1.0.0:
|
|||||||
and version 2.2.x database files will be identical and completely
|
and version 2.2.x database files will be identical and completely
|
||||||
interchangeable.</p>
|
interchangeable.</p>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top">2.2.5 to 2.3.0</td>
|
||||||
|
<td valign="top">2002-Jan-30</td>
|
||||||
|
<td>Beginning with version 2.3.0, SQLite supports some additional syntax
|
||||||
|
(the "ON CONFLICT" clause) in the CREATE TABLE and CREATE INDEX statements
|
||||||
|
that are stored in the SQLITE_MASTER table. If you create a database that
|
||||||
|
contains this new syntax, then try to read that database using version 2.2.5
|
||||||
|
or earlier, the parser will not understand the new syntax and you will get
|
||||||
|
an error. Otherwise, databases for 2.2.x and 2.3.x are interchangeable.</p>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
|
112
www/lang.tcl
112
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.18 2001/12/22 19:27:41 drh Exp $}
|
set rcsid {$Id: lang.tcl,v 1.19 2002/01/30 16:17:25 drh Exp $}
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -31,7 +31,7 @@ by SQLite. Many low-level productions are omitted. For detailed information
|
|||||||
on the language that SQLite understands, refer to the source code.</p>
|
on the language that SQLite understands, refer to the source code.</p>
|
||||||
|
|
||||||
|
|
||||||
<p>SQLite implements the follow SQL commands:</p>
|
<p>SQLite implements the follow syntax:</p>
|
||||||
<p><ul>
|
<p><ul>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +50,7 @@ foreach {section} [lsort -index 0 -dictionary {
|
|||||||
{expression expr}
|
{expression expr}
|
||||||
{{BEGIN TRANSACTION} transaction}
|
{{BEGIN TRANSACTION} transaction}
|
||||||
{PRAGMA pragma}
|
{PRAGMA pragma}
|
||||||
|
{{ON CONFLICT clause} conflict}
|
||||||
}] {
|
}] {
|
||||||
puts "<li><a href=\"#[lindex $section 1]\">[lindex $section 0]</a></li>"
|
puts "<li><a href=\"#[lindex $section 1]\">[lindex $section 0]</a></li>"
|
||||||
}
|
}
|
||||||
@@ -140,12 +141,47 @@ a alias for COMMIT.
|
|||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Section {ON CONFLICT clause} conflict
|
||||||
|
|
||||||
|
Syntax {conflict-clause} {
|
||||||
|
ON CONFLICT <algorithm>
|
||||||
|
} {algorithm} {
|
||||||
|
ABORT | IGNORE | REPLACE
|
||||||
|
}
|
||||||
|
|
||||||
|
puts {
|
||||||
|
<p>The ON CONFLICT clause is not a separate SQL command. It is a
|
||||||
|
non-standard clause that can appear in many other SQL commands.
|
||||||
|
It is given its own section in this document because it is not
|
||||||
|
part of standard SQL and therefore might not be familiar.</p>
|
||||||
|
|
||||||
|
<p>The ON CONFLICT clause specifies an algorithm used to resolve
|
||||||
|
constraint conflicts. The default algorithm is ABORT. When the
|
||||||
|
ABORT algorithm is in use, any constraint violation causes the
|
||||||
|
command to abort and the current transaction to be rolled back.
|
||||||
|
This is the only behavior exhibited by most SQL engines. But
|
||||||
|
SQLite allows two alternative behaviors: IGNORE and REPLACE.
|
||||||
|
The IGNORE algorithm means that when a constraint violation occurs
|
||||||
|
on a COPY, INSERT or UPDATE, the particular row that caused the constraint
|
||||||
|
violation is not inserted or changed, but other rows effected by the
|
||||||
|
COPY, INSERT, or UPDATE are insert or changed as usual.
|
||||||
|
The command is not aborted and no rollback occurs.
|
||||||
|
If the algorithm is REPLACE, then SQLite tries to
|
||||||
|
delete preexisting rows from the table to remove the constraint
|
||||||
|
violation before inserting or changing the row.</p>
|
||||||
|
|
||||||
|
<p>For additional information, see
|
||||||
|
<a href="conflict.html">conflict.html</a>.</p>
|
||||||
|
}
|
||||||
|
|
||||||
Section COPY copy
|
Section COPY copy
|
||||||
|
|
||||||
Syntax {sql-statement} {
|
Syntax {sql-statement} {
|
||||||
COPY <table-name> FROM <filename>
|
COPY [ <conflict-clause> ] <table-name> FROM <filename>
|
||||||
|
[ USING DELIMITERS <delim> ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
puts {
|
puts {
|
||||||
<p>The COPY command is an extension used to load large amounts of
|
<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
|
data into a table. It is modeled after a similar command found
|
||||||
@@ -163,7 +199,16 @@ the <b>STDIN</b> to read data from standard input.<p>
|
|||||||
in the table. Columns are separated by tabs. If a tab occurs as
|
in the table. Columns are separated by tabs. If a tab occurs as
|
||||||
data within a column, then that tab is preceded by a baskslash "\"
|
data within a column, then that tab is preceded by a baskslash "\"
|
||||||
character. A baskslash in the data appears as two backslashes in
|
character. A baskslash in the data appears as two backslashes in
|
||||||
a row.</p>
|
a row. The optional USING DELIMITERS clause can specify a delimiter
|
||||||
|
other than tab.</p>
|
||||||
|
|
||||||
|
<p>If a column consists of the character "\N", that column is filled
|
||||||
|
with the value NULL.</p>
|
||||||
|
|
||||||
|
<p>The optional conflict-clause allows the specification of an alternative
|
||||||
|
constraint conflict resolution algorithm to use for this one command.
|
||||||
|
See the section titled
|
||||||
|
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
|
||||||
|
|
||||||
<p>When the input data source is STDIN, the input can be terminated
|
<p>When the input data source is STDIN, the input can be terminated
|
||||||
by a line that contains only a baskslash and a dot:}
|
by a line that contains only a baskslash and a dot:}
|
||||||
@@ -174,10 +219,12 @@ 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> ]
|
||||||
} {column-name} {
|
} {column-name} {
|
||||||
<name> [ ASC | DESC ]
|
<name> [ ASC | DESC ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
puts {
|
puts {
|
||||||
<p>The CREATE INDEX command consists of the keywords "CREATE INDEX" followed
|
<p>The CREATE INDEX command consists of the keywords "CREATE INDEX" followed
|
||||||
by the name of the new index, the keyword "ON", the name of a previously
|
by the name of the new index, the keyword "ON", the name of a previously
|
||||||
@@ -194,6 +241,16 @@ attached to a single table, nor on the number of columns in an index.</p>
|
|||||||
index entries are not allowed. Any attempt to insert a duplicate entry
|
index entries are not allowed. Any attempt to insert a duplicate entry
|
||||||
will result in a rollback and an error message.</p>
|
will result in a rollback and an error message.</p>
|
||||||
|
|
||||||
|
<p>The optional conflict-clause allows the specification of al alternative
|
||||||
|
default constraint conflict resolution algorithm for this index.
|
||||||
|
This only makes sense if the UNIQUE keyword is used since otherwise
|
||||||
|
there are not constraints on the index. The default algorithm is
|
||||||
|
ABORT. If a COPY, INSERT, or UPDATE statement specifies a particular
|
||||||
|
conflict resolution algorithm, that algorithm is used in place of
|
||||||
|
the default algorithm specified here.
|
||||||
|
See the section titled
|
||||||
|
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
|
||||||
|
|
||||||
<p>The exact text
|
<p>The exact text
|
||||||
of each CREATE INDEX statement is stored in the <b>sqlite_master</b>
|
of each CREATE INDEX statement is stored in the <b>sqlite_master</b>
|
||||||
table. Everytime the database is opened, all CREATE INDEX statements
|
table. Everytime the database is opened, all CREATE INDEX statements
|
||||||
@@ -216,15 +273,15 @@ CREATE [TEMP | TEMPORARY] TABLE <table-name> (
|
|||||||
<typename> ( <number> ) |
|
<typename> ( <number> ) |
|
||||||
<typename> ( <number> , <number> )
|
<typename> ( <number> , <number> )
|
||||||
} {column-constraint} {
|
} {column-constraint} {
|
||||||
NOT NULL |
|
NOT NULL [ <conflict-clause> ] |
|
||||||
PRIMARY KEY [<sort-order>] |
|
PRIMARY KEY [<sort-order>] [ <conflict-clause> ] |
|
||||||
UNIQUE |
|
UNIQUE [ <conflict-clause> ] |
|
||||||
CHECK ( <expr> ) |
|
CHECK ( <expr> ) [ <conflict-clause> ] |
|
||||||
DEFAULT <value>
|
DEFAULT <value>
|
||||||
} {constraint} {
|
} {constraint} {
|
||||||
PRIMARY KEY ( <name> [, <name>]* ) |
|
PRIMARY KEY ( <name> [, <name>]* ) [ <conflict-clause> ]|
|
||||||
UNIQUE ( <name> [, <name>]* ) |
|
UNIQUE ( <name> [, <name>]* ) [ <conflict-clause> ] |
|
||||||
CHECK ( <expr> )
|
CHECK ( <expr> ) [ <conflict-clause> ]
|
||||||
}
|
}
|
||||||
|
|
||||||
puts {
|
puts {
|
||||||
@@ -265,6 +322,17 @@ the database is closed. Any indices created on a temporary table
|
|||||||
are also temporary. Temporary tables and indices are stored in a
|
are also temporary. Temporary tables and indices are stored in a
|
||||||
separate file distinct from the main database file.</p>
|
separate file distinct from the main database file.</p>
|
||||||
|
|
||||||
|
<p>The optional conflict-clause following each constraint
|
||||||
|
allows the specification of an alternative default
|
||||||
|
constraint conflict resolution algorithm for that constraint.
|
||||||
|
The default is abort ABORT. Different constraints within the same
|
||||||
|
table may have different default conflict resolution algorithms.
|
||||||
|
If an COPY, INSERT, or UPDATE command specifies a different conflict
|
||||||
|
resolution algorithm, then that algorithm is used in place of the
|
||||||
|
default algorithm specified in the CREATE TABLE statement.
|
||||||
|
See the section titled
|
||||||
|
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
|
||||||
|
|
||||||
<p>There are no arbitrary limits on the number
|
<p>There are no arbitrary limits on the number
|
||||||
of columns or on the number of constraints in a table.
|
of columns or on the number of constraints in a table.
|
||||||
The total amount of data in a single row is limited to about
|
The total amount of data in a single row is limited to about
|
||||||
@@ -363,7 +431,7 @@ LIKE | GLOB | NOT LIKE | NOT GLOB
|
|||||||
}
|
}
|
||||||
|
|
||||||
puts {
|
puts {
|
||||||
<p>This section is different from the others. Every other section of
|
<p>This section is different from the others. Most other sections of
|
||||||
this document talks about a particular SQL command. This section does
|
this document talks about a particular SQL command. This section does
|
||||||
not talk about a standalone command but about "expressions" which are
|
not talk about a standalone command but about "expressions" which are
|
||||||
subcomponent of most other commands.</p>
|
subcomponent of most other commands.</p>
|
||||||
@@ -490,8 +558,8 @@ The "<b>count(*)</b>" syntax is supported but
|
|||||||
Section INSERT insert
|
Section INSERT insert
|
||||||
|
|
||||||
Syntax {sql-statement} {
|
Syntax {sql-statement} {
|
||||||
INSERT INTO <table-name> [( <column-list> )] VALUES ( <value-list> ) |
|
INSERT [ <conflict-clause> ] INTO <table-name> [( <column-list> )] VALUES ( <value-list> ) |
|
||||||
INSERT INTO <table-name> [( <column-list> )] <select-statement>
|
INSERT [ <conflict-clause> ] INTO <table-name> [( <column-list> )] <select-statement>
|
||||||
}
|
}
|
||||||
|
|
||||||
puts {
|
puts {
|
||||||
@@ -513,6 +581,11 @@ name in the column list. A new entry is made in the table
|
|||||||
for every row of the SELECT result. The SELECT may be simple
|
for every row of the SELECT result. The SELECT may be simple
|
||||||
or compound. If the SELECT statement has an ORDER BY clause,
|
or compound. If the SELECT statement has an ORDER BY clause,
|
||||||
the ORDER BY is ignored.</p>
|
the ORDER BY is ignored.</p>
|
||||||
|
|
||||||
|
<p>The optional conflict-clause allows the specification of an alternative
|
||||||
|
constraint conflict resolution algorithm to use during this one command.
|
||||||
|
See the section titled
|
||||||
|
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
Section SELECT select
|
Section SELECT select
|
||||||
@@ -597,7 +670,9 @@ 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 <table-name> SET <assignment> [, <assignment>] [WHERE <expression>]
|
UPDATE [ <conflict-clause> ] <table-name>
|
||||||
|
SET <assignment> [, <assignment>]
|
||||||
|
[WHERE <expression>]
|
||||||
} {assignment} {
|
} {assignment} {
|
||||||
<column-name> = <expression>
|
<column-name> = <expression>
|
||||||
}
|
}
|
||||||
@@ -608,7 +683,12 @@ selected rows of a table. Each assignment in an UPDATE specifies
|
|||||||
a column name to the left of the equals sign and an arbitrary expression
|
a column name to the left of the equals sign and an arbitrary expression
|
||||||
to the right. The expressions may use the values of other columns.
|
to the right. The expressions may use the values of other columns.
|
||||||
All expressions are evaluated before any assignments are made.
|
All expressions are evaluated before any assignments are made.
|
||||||
A WHERE clause can be used to restrict which rows are updated.
|
A WHERE clause can be used to restrict which rows are updated.</p>
|
||||||
|
|
||||||
|
<p>The optional conflict-clause allows the specification of an alternative
|
||||||
|
constraint conflict resolution algorithm to use during this one command.
|
||||||
|
See the section titled
|
||||||
|
<a href="#conflict">ON CONFLICT</a> for additional information.</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
Section VACUUM vacuum
|
Section VACUUM vacuum
|
||||||
|
Reference in New Issue
Block a user