mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Fix some issues with UPDATE changes in the session module.
FossilOrigin-Name: 57862efe718fdc93401998f9058511292a0e1a50
This commit is contained in:
@ -667,14 +667,14 @@ static void sessionAppendUpdate(
|
|||||||
u8 *pCsr = p->aRecord;
|
u8 *pCsr = p->aRecord;
|
||||||
sessionAppendByte(pBuf, SQLITE_UPDATE, pRc);
|
sessionAppendByte(pBuf, SQLITE_UPDATE, pRc);
|
||||||
for(i=0; i<sqlite3_column_count(pStmt); i++){
|
for(i=0; i<sqlite3_column_count(pStmt); i++){
|
||||||
int nCopy = 0;
|
int bChanged = 0;
|
||||||
int nAdvance;
|
int nAdvance;
|
||||||
int eType = *pCsr;
|
int eType = *pCsr;
|
||||||
switch( eType ){
|
switch( eType ){
|
||||||
case SQLITE_NULL:
|
case SQLITE_NULL:
|
||||||
nAdvance = 1;
|
nAdvance = 1;
|
||||||
if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
|
if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
|
||||||
nCopy = 1;
|
bChanged = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -691,7 +691,7 @@ static void sessionAppendUpdate(
|
|||||||
if( dVal==sqlite3_column_double(pStmt, i) ) break;
|
if( dVal==sqlite3_column_double(pStmt, i) ) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nCopy = 9;
|
bChanged = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,21 +706,23 @@ static void sessionAppendUpdate(
|
|||||||
){
|
){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
nCopy = nAdvance;
|
bChanged = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( abPK[i] ){
|
|
||||||
nCopy = nAdvance;
|
if( bChanged || abPK[i] ){
|
||||||
|
sessionAppendBlob(pBuf, pCsr, nAdvance, pRc);
|
||||||
|
}else{
|
||||||
|
sessionAppendByte(pBuf, 0, pRc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nCopy==0 ){
|
if( bChanged ){
|
||||||
sessionAppendByte(pBuf, 0, pRc);
|
|
||||||
sessionAppendByte(&buf2, 0, pRc);
|
|
||||||
}else{
|
|
||||||
sessionAppendBlob(pBuf, pCsr, nCopy, pRc);
|
|
||||||
sessionAppendCol(&buf2, pStmt, i, pRc);
|
sessionAppendCol(&buf2, pStmt, i, pRc);
|
||||||
bNoop = 0;
|
bNoop = 0;
|
||||||
|
}else{
|
||||||
|
sessionAppendByte(&buf2, 0, pRc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pCsr += nAdvance;
|
pCsr += nAdvance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1452,6 +1454,52 @@ static int sessionSelectRow(
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sessionConstraintConflict(
|
||||||
|
sqlite3 *db, /* Database handle */
|
||||||
|
sqlite3_changeset_iter *pIter, /* Changeset iterator */
|
||||||
|
u8 *abPK, /* Primary key flags array */
|
||||||
|
sqlite3_stmt *pSelect, /* SELECT statement from sessionSelectRow() */
|
||||||
|
int(*xConflict)(void *, int, sqlite3_changeset_iter*),
|
||||||
|
void *pCtx
|
||||||
|
){
|
||||||
|
int res;
|
||||||
|
int rc;
|
||||||
|
int i;
|
||||||
|
int nCol;
|
||||||
|
int op;
|
||||||
|
const char *zDummy;
|
||||||
|
|
||||||
|
sqlite3changeset_op(pIter, &zDummy, &nCol, &op);
|
||||||
|
assert( op==SQLITE_UPDATE || op==SQLITE_INSERT );
|
||||||
|
|
||||||
|
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
|
||||||
|
for(i=0; i<nCol; i++){
|
||||||
|
if( abPK[i] ){
|
||||||
|
sqlite3_value *pVal;
|
||||||
|
if( op==SQLITE_UPDATE ) rc = sqlite3changeset_old(pIter, i, &pVal);
|
||||||
|
else rc = sqlite3changeset_new(pIter, i, &pVal);
|
||||||
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
|
sqlite3_bind_value(pSelect, i+1, pVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( SQLITE_ROW==sqlite3_step(pSelect) ){
|
||||||
|
/* There exists another row with the new.* primary key. */
|
||||||
|
pIter->pConflict = pSelect;
|
||||||
|
res = xConflict(pCtx, SQLITE_CHANGESET_CONFLICT, pIter);
|
||||||
|
pIter->pConflict = 0;
|
||||||
|
sqlite3_reset(pSelect);
|
||||||
|
}else{
|
||||||
|
/* No other row with the new.* primary key. */
|
||||||
|
rc = sqlite3_reset(pSelect);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
res = xConflict(pCtx, SQLITE_CHANGESET_CONSTRAINT, pIter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int sqlite3changeset_apply(
|
int sqlite3changeset_apply(
|
||||||
sqlite3 *db,
|
sqlite3 *db,
|
||||||
int nChangeset,
|
int nChangeset,
|
||||||
@ -1479,6 +1527,8 @@ int sqlite3changeset_apply(
|
|||||||
sqlite3_stmt *pSelect = 0; /* SELECT statement */
|
sqlite3_stmt *pSelect = 0; /* SELECT statement */
|
||||||
|
|
||||||
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
|
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
|
||||||
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
|
|
||||||
sqlite3changeset_start(&pIter, nChangeset, pChangeset);
|
sqlite3changeset_start(&pIter, nChangeset, pChangeset);
|
||||||
while( SQLITE_ROW==sqlite3changeset_next(pIter) ){
|
while( SQLITE_ROW==sqlite3changeset_next(pIter) ){
|
||||||
int op;
|
int op;
|
||||||
@ -1494,6 +1544,13 @@ int sqlite3changeset_apply(
|
|||||||
sqlite3_finalize(pInsert);
|
sqlite3_finalize(pInsert);
|
||||||
sqlite3_finalize(pSelect);
|
sqlite3_finalize(pSelect);
|
||||||
pSelect = pUpdate = pInsert = pDelete = 0;
|
pSelect = pUpdate = pInsert = pDelete = 0;
|
||||||
|
|
||||||
|
if( (rc = sessionSelectRow(db, zTab, nCol, azCol, abPK, &pSelect))
|
||||||
|
|| (rc = sessionUpdateRow(db, zTab, nCol, azCol, abPK, &pUpdate))
|
||||||
|
|| (rc = sessionDeleteRow(db, zTab, nCol, azCol, abPK, &pDelete))
|
||||||
|
){
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( op==SQLITE_DELETE ){
|
if( op==SQLITE_DELETE ){
|
||||||
@ -1559,7 +1616,7 @@ int sqlite3changeset_apply(
|
|||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
if( pOld ) sqlite3_bind_value(pUpdate, i*3+1, pOld);
|
if( pOld ) sqlite3_bind_value(pUpdate, i*3+1, pOld);
|
||||||
sqlite3_bind_int(pUpdate, i*3+2, !!pNew);
|
sqlite3_bind_int(pUpdate, i*3+2, !!pNew);
|
||||||
if( pNew ) sqlite3_bind_value(pUpdate, i*3+3, pOld);
|
if( pNew ) sqlite3_bind_value(pUpdate, i*3+3, pNew);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_OK ) rc = sqlite3_bind_int(pUpdate, nCol*3+1, 0);
|
if( rc==SQLITE_OK ) rc = sqlite3_bind_int(pUpdate, nCol*3+1, 0);
|
||||||
@ -1592,7 +1649,32 @@ int sqlite3changeset_apply(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if( rc==SQLITE_CONSTRAINT ){
|
}else if( rc==SQLITE_CONSTRAINT ){
|
||||||
assert(0);
|
/* This may be a CONSTRAINT or CONFLICT error. It is a CONFLICT if
|
||||||
|
** the only problem is a duplicate PRIMARY KEY, or a CONSTRAINT
|
||||||
|
** otherwise. */
|
||||||
|
int bPKChange = 0;
|
||||||
|
|
||||||
|
/* Check if the PK has been modified. */
|
||||||
|
rc = SQLITE_OK;
|
||||||
|
for(i=0; i<nCol && rc==SQLITE_OK; i++){
|
||||||
|
if( abPK[i] ){
|
||||||
|
sqlite3_value *pNew;
|
||||||
|
rc = sqlite3changeset_new(pIter, i, &pNew);
|
||||||
|
if( rc==SQLITE_OK && pNew ){
|
||||||
|
bPKChange = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bPKChange ){
|
||||||
|
/* See if there exists a row with a duplicate primary key. */
|
||||||
|
rc = sessionConstraintConflict(
|
||||||
|
db, pIter, abPK, pSelect, xConflict, pCtx
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
res = xConflict(pCtx, SQLITE_CHANGESET_CONSTRAINT, pIter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
@ -1624,29 +1706,9 @@ int sqlite3changeset_apply(
|
|||||||
sqlite3_step(pInsert);
|
sqlite3_step(pInsert);
|
||||||
rc = sqlite3_reset(pInsert);
|
rc = sqlite3_reset(pInsert);
|
||||||
if( rc==SQLITE_CONSTRAINT && xConflict ){
|
if( rc==SQLITE_CONSTRAINT && xConflict ){
|
||||||
int res;
|
rc = sessionConstraintConflict(
|
||||||
|
db, pIter, abPK, pSelect, xConflict, pCtx
|
||||||
/* Figure out if this is a primary key or other constraint. */
|
);
|
||||||
rc = sessionSelectRow(db, zTab, nCol, azCol, abPK, &pSelect);
|
|
||||||
for(i=0; rc==SQLITE_OK && i<nCol; i++){
|
|
||||||
if( abPK[i] ){
|
|
||||||
sqlite3_value *pVal;
|
|
||||||
rc = sqlite3changeset_new(pIter, i, &pVal);
|
|
||||||
if( rc==SQLITE_OK ) sqlite3_bind_value(pSelect, i+1, pVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( rc!=SQLITE_OK ) break;
|
|
||||||
if( SQLITE_ROW==sqlite3_step(pSelect) ){
|
|
||||||
pIter->pConflict = pSelect;
|
|
||||||
res = xConflict(pCtx, SQLITE_CHANGESET_CONFLICT, pIter);
|
|
||||||
pIter->pConflict = 0;
|
|
||||||
sqlite3_reset(pSelect);
|
|
||||||
}else{
|
|
||||||
rc = sqlite3_reset(pSelect);
|
|
||||||
if( rc==SQLITE_OK ){
|
|
||||||
res = xConflict(pCtx, SQLITE_CHANGESET_CONSTRAINT, pIter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
|||||||
C Add\sthe\ssqlite3changeset_apply()\sfunction.\sDoes\snot\syet\shandle\sall\scases.
|
C Fix\ssome\sissues\swith\sUPDATE\schanges\sin\sthe\ssession\smodule.
|
||||||
D 2011-03-11T19:05:52
|
D 2011-03-12T17:22:46
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@ -98,7 +98,7 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
|||||||
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
|
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
|
||||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||||
F ext/session/sqlite3session.c 724a064f0d9a909c12dfb668b42ce007378f352e
|
F ext/session/sqlite3session.c af63d87b8787c19b4a4b681f77331a9cc13d67af
|
||||||
F ext/session/sqlite3session.h 3246613b20857e58f7419e4e26dbe9161677aff0
|
F ext/session/sqlite3session.h 3246613b20857e58f7419e4e26dbe9161677aff0
|
||||||
F ext/session/test_session.c 1b4f278d0ae164e2d02c11f5e1f2df3a2567ba41
|
F ext/session/test_session.c 1b4f278d0ae164e2d02c11f5e1f2df3a2567ba41
|
||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||||
@ -639,7 +639,7 @@ F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
|
|||||||
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
|
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
|
||||||
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
|
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
|
||||||
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
||||||
F test/session1.test 6a2e0db809e44879cec5314a6fd238ad768d9723
|
F test/session1.test 6ec522f3491fbdbf8a5b6c27f50b9e35f24e3dba
|
||||||
F test/shared.test b9114eaea7e748a3a4c8ff7b9ca806c8f95cef3e
|
F test/shared.test b9114eaea7e748a3a4c8ff7b9ca806c8f95cef3e
|
||||||
F test/shared2.test 7f6ad2d857d0f4e5d6a0b9a897b5e56a6b6ea18c
|
F test/shared2.test 7f6ad2d857d0f4e5d6a0b9a897b5e56a6b6ea18c
|
||||||
F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962
|
F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962
|
||||||
@ -913,7 +913,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
|||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||||
P 75d5dff725dbb66d67d56ad042926f1daae56dbe
|
P 2b19be7bf753c7dd12e1c3b384981a3ea1bc8145
|
||||||
R 7203b6a6763bad83d70ecbe2db2167c5
|
R 222ffce3b378b2ba18950183bb251367
|
||||||
U dan
|
U dan
|
||||||
Z 77d8992b93ad5a2a0231fb47a635b3cb
|
Z b642b18410bb67d03067201d5612ecd6
|
||||||
|
@ -1 +1 @@
|
|||||||
2b19be7bf753c7dd12e1c3b384981a3ea1bc8145
|
57862efe718fdc93401998f9058511292a0e1a50
|
@ -259,22 +259,29 @@ do_execsql_test 3.3.1 {
|
|||||||
CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c));
|
CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c));
|
||||||
INSERT INTO t4 VALUES(1, 2, 3);
|
INSERT INTO t4 VALUES(1, 2, 3);
|
||||||
INSERT INTO t4 VALUES(4, 5, 6);
|
INSERT INTO t4 VALUES(4, 5, 6);
|
||||||
|
INSERT INTO t4 VALUES(7, 8, 9);
|
||||||
|
INSERT INTO t4 VALUES(10, 11, 12);
|
||||||
}
|
}
|
||||||
do_db2_test 3.3.2 {
|
do_db2_test 3.3.2 {
|
||||||
CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c));
|
CREATE TABLE t4(a NOT NULL, b, c, PRIMARY KEY(b, c));
|
||||||
INSERT INTO t4 VALUES(0, 2, 3);
|
INSERT INTO t4 VALUES(0, 2, 3);
|
||||||
INSERT INTO t4 VALUES(4, 5, 7);
|
INSERT INTO t4 VALUES(4, 5, 7);
|
||||||
|
INSERT INTO t4 VALUES(7, 8, 9);
|
||||||
|
INSERT INTO t4 VALUES(10, 11, 12);
|
||||||
}
|
}
|
||||||
|
do_conflict_test 3.3.3 -tables t4 -sql {
|
||||||
do_conflict_test 3.2.3 -tables t4 -sql {
|
|
||||||
UPDATE t4 SET a = -1 WHERE b = 2;
|
UPDATE t4 SET a = -1 WHERE b = 2;
|
||||||
|
UPDATE t4 SET a = -1 WHERE b = 5;
|
||||||
|
UPDATE t4 SET a = NULL WHERE c = 9;
|
||||||
|
UPDATE t4 SET a = 'x' WHERE b = 11;
|
||||||
} -conflicts {
|
} -conflicts {
|
||||||
{UPDATE t4 DATA {i 1 i 2 i 3} {i -1 i 2 i 3} {i 0 i 2 i 3}}
|
{UPDATE t4 DATA {i 1 i 2 i 3} {i -1 {} {} {} {}} {i 0 i 2 i 3}}
|
||||||
|
{UPDATE t4 NOTFOUND {i 4 i 5 i 6} {i -1 {} {} {} {}}}
|
||||||
|
{UPDATE t4 CONSTRAINT {i 7 i 8 i 9} {n {} {} {} {} {}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_db2_test 3.3.4 {
|
do_db2_test 3.3.4 { SELECT * FROM t4 } {0 2 3 4 5 7 7 8 9 x 11 12}
|
||||||
SELECT * FROM t4
|
do_execsql_test 3.3.5 { SELECT * FROM t4 } {-1 2 3 -1 5 6 {} 8 9 x 11 12}
|
||||||
} {0 2 3 4 5 7}
|
|
||||||
|
|
||||||
|
|
||||||
catch { db2 close }
|
catch { db2 close }
|
||||||
|
Reference in New Issue
Block a user