mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Fix handling of schema mismatches in sqlite3session.c so that it matches the docs in sqlite3session.h.
FossilOrigin-Name: 506a0d7a710e1ff2f367821e73f5080fcf63fbc5
This commit is contained in:
88
ext/session/session3.test
Normal file
88
ext/session/session3.test
Normal file
@ -0,0 +1,88 @@
|
||||
# 2011 March 24
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for the session module.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] session_common.tcl]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
set testprefix session3
|
||||
|
||||
# These tests - session3-1.* - verify that the session module behaves
|
||||
# correctly when confronted with a schema mismatch when applying a
|
||||
# changeset (in function sqlite3changeset_apply()).
|
||||
#
|
||||
# session3-1.1.*: Table does not exist in target db.
|
||||
# session3-1.2.*: Table has wrong number of columns in target db.
|
||||
# session3-1.3.*: Table has wrong PK columns in target db.
|
||||
#
|
||||
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
test_sqlite3_log log
|
||||
sqlite3 db test.db
|
||||
|
||||
proc log {code msg} { lappend ::log $code $msg }
|
||||
|
||||
forcedelete test.db2
|
||||
sqlite3 db2 test.db2
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
}
|
||||
do_test 1.1 {
|
||||
set ::log {}
|
||||
do_then_apply_sql {
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
}
|
||||
set ::log
|
||||
} {SQLITE_SCHEMA {sqlite3changeset_apply(): no such table: t1}}
|
||||
|
||||
do_test 1.2.0 {
|
||||
execsql { CREATE TABLE t1(a PRIMARY KEY, b, c) } db2
|
||||
} {}
|
||||
do_test 1.2.1 {
|
||||
set ::log {}
|
||||
do_then_apply_sql {
|
||||
INSERT INTO t1 VALUES(5, 6);
|
||||
INSERT INTO t1 VALUES(7, 8);
|
||||
}
|
||||
set ::log
|
||||
} {SQLITE_SCHEMA {sqlite3changeset_apply(): table t1 has 3 columns, expected 2}}
|
||||
|
||||
do_test 1.3.0 {
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a, b PRIMARY KEY);
|
||||
} db2
|
||||
} {}
|
||||
do_test 1.3.1 {
|
||||
set ::log {}
|
||||
do_then_apply_sql {
|
||||
INSERT INTO t1 VALUES(9, 10);
|
||||
INSERT INTO t1 VALUES(11, 12);
|
||||
}
|
||||
set ::log
|
||||
} {SQLITE_SCHEMA {sqlite3changeset_apply(): primary key mismatch for table t1}}
|
||||
|
||||
|
||||
catch { db close }
|
||||
catch { db2 close }
|
||||
sqlite3_shutdown
|
||||
test_sqlite3_log
|
||||
sqlite3_initialize
|
||||
|
||||
finish_test
|
||||
|
@ -544,7 +544,7 @@ static int sessionTableInfo(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zDb, /* Name of attached database (e.g. "main") */
|
||||
const char *zThis, /* Table name */
|
||||
int nCol, /* Expected number of columns */
|
||||
int *pnCol, /* OUT: number of columns */
|
||||
const char **pzTab, /* OUT: Copy of zThis */
|
||||
const char ***pazCol, /* OUT: Array of column names for table */
|
||||
u8 **pabPK /* OUT: Array of booleans - true for PK col */
|
||||
@ -577,9 +577,6 @@ static int sessionTableInfo(
|
||||
}
|
||||
rc = sqlite3_reset(pStmt);
|
||||
|
||||
if( nDbCol!=nCol ){
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
|
||||
pAlloc = sqlite3_malloc(nByte);
|
||||
@ -589,9 +586,9 @@ static int sessionTableInfo(
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
azCol = (char **)pAlloc;
|
||||
pAlloc = (u8 *)&azCol[nCol];
|
||||
pAlloc = (u8 *)&azCol[nDbCol];
|
||||
abPK = (u8 *)pAlloc;
|
||||
pAlloc = &abPK[nCol];
|
||||
pAlloc = &abPK[nDbCol];
|
||||
if( pzTab ){
|
||||
memcpy(pAlloc, zThis, nThis+1);
|
||||
*pzTab = (char *)pAlloc;
|
||||
@ -619,9 +616,11 @@ static int sessionTableInfo(
|
||||
if( rc==SQLITE_OK ){
|
||||
*pazCol = (const char **)azCol;
|
||||
*pabPK = abPK;
|
||||
*pnCol = nDbCol;
|
||||
}else{
|
||||
*pazCol = 0;
|
||||
*pabPK = 0;
|
||||
*pnCol = 0;
|
||||
if( pzTab ) *pzTab = 0;
|
||||
sqlite3_free(azCol);
|
||||
}
|
||||
@ -648,11 +647,13 @@ static int sessionTableInfo(
|
||||
static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
|
||||
if( pTab->nCol==0 ){
|
||||
assert( pTab->azCol==0 || pTab->abPK==0 );
|
||||
pTab->nCol = sqlite3_preupdate_count(pSession->db);
|
||||
pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
|
||||
pTab->zName, pTab->nCol, 0, &pTab->azCol, &pTab->abPK
|
||||
pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->abPK
|
||||
);
|
||||
}else if( pTab->nCol!=sqlite3_preupdate_count(pSession->db) ){
|
||||
}
|
||||
if( pSession->rc==SQLITE_OK
|
||||
&& pTab->nCol!=sqlite3_preupdate_count(pSession->db)
|
||||
){
|
||||
pSession->rc = SQLITE_SCHEMA;
|
||||
}
|
||||
return pSession->rc;
|
||||
@ -2402,6 +2403,7 @@ int sqlite3changeset_apply(
|
||||
),
|
||||
void *pCtx /* First argument passed to xConflict */
|
||||
){
|
||||
int schemaMismatch = 0;
|
||||
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
||||
int rc; /* Return code */
|
||||
const char *zTab = 0; /* Name of current table */
|
||||
@ -2420,9 +2422,13 @@ int sqlite3changeset_apply(
|
||||
int bReplace = 0;
|
||||
int bRetry = 0;
|
||||
const char *zNew;
|
||||
|
||||
sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
|
||||
|
||||
if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
|
||||
u8 *abPK;
|
||||
|
||||
schemaMismatch = 0;
|
||||
sqlite3_free(sApply.azCol);
|
||||
sqlite3_finalize(sApply.pDelete);
|
||||
sqlite3_finalize(sApply.pUpdate);
|
||||
@ -2430,23 +2436,47 @@ int sqlite3changeset_apply(
|
||||
sqlite3_finalize(sApply.pSelect);
|
||||
memset(&sApply, 0, sizeof(sApply));
|
||||
sApply.db = db;
|
||||
sApply.nCol = nCol;
|
||||
|
||||
sqlite3changeset_pk(pIter, &abPK, 0);
|
||||
rc = sessionTableInfo(
|
||||
db, "main", zNew, nCol, &zTab, &sApply.azCol, &sApply.abPK);
|
||||
db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
|
||||
);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
|
||||
if( rc!=SQLITE_OK
|
||||
|| (rc = sessionSelectRow(db, zTab, &sApply))
|
||||
if( sApply.nCol==0 ){
|
||||
schemaMismatch = 1;
|
||||
sqlite3_log(SQLITE_SCHEMA,
|
||||
"sqlite3changeset_apply(): no such table: %s", zTab
|
||||
);
|
||||
}
|
||||
else if( sApply.nCol!=nCol ){
|
||||
schemaMismatch = 1;
|
||||
sqlite3_log(SQLITE_SCHEMA,
|
||||
"sqlite3changeset_apply(): table %s has %d columns, expected %d",
|
||||
zTab, sApply.nCol, nCol
|
||||
);
|
||||
}
|
||||
else if( memcmp(sApply.abPK, abPK, nCol)!=0 ){
|
||||
schemaMismatch = 1;
|
||||
sqlite3_log(SQLITE_SCHEMA,
|
||||
"sqlite3changeset_apply(): primary key mismatch for table %s", zTab
|
||||
);
|
||||
}
|
||||
else if(
|
||||
(rc = sessionSelectRow(db, zTab, &sApply))
|
||||
|| (rc = sessionUpdateRow(db, zTab, &sApply))
|
||||
|| (rc = sessionDeleteRow(db, zTab, &sApply))
|
||||
|| (rc = sessionInsertRow(db, zTab, &sApply))
|
||||
){
|
||||
break;
|
||||
}
|
||||
|
||||
nTab = strlen(zTab);
|
||||
}
|
||||
|
||||
/* If there is a schema mismatch on the current table, proceed to the
|
||||
** next change. A log message has already been issued. */
|
||||
if( schemaMismatch ) continue;
|
||||
|
||||
rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, &bRetry);
|
||||
|
||||
if( rc==SQLITE_OK && bRetry ){
|
||||
|
@ -48,7 +48,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
|
||||
**
|
||||
** The session object will be used to create changesets for tables in
|
||||
** database zDb, where zDb is either "main", or "temp", or the name of an
|
||||
** attached database. It is not an error if database zDb does not exist
|
||||
** attached database. It is not an error if database zDb is not attached
|
||||
** to the database when the session object is created.
|
||||
*/
|
||||
int sqlite3session_create(
|
||||
|
15
manifest
15
manifest
@ -1,5 +1,5 @@
|
||||
C Store\sprimary\skey\sdefinitions\sfor\smodified\stables\sin\schangesets.\sAdd\sthe\ssqlite3changeset_pk()\sAPI\sto\sextract\sthis\sdata\sfrom\sa\schangeset\siterator.
|
||||
D 2011-03-24T11:22:59
|
||||
C Fix\shandling\sof\sschema\smismatches\sin\ssqlite3session.c\sso\sthat\sit\smatches\sthe\sdocs\sin\ssqlite3session.h.
|
||||
D 2011-03-24T16:04:55
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -101,10 +101,11 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F ext/session/session1.test b2da15b9d727d7f4e5fe95599b32b92d93b5a970
|
||||
F ext/session/session2.test 8da094318ac88953478c43d0bfb0aa723ee0e379
|
||||
F ext/session/session3.test b8b9ff7efcb19234892c406dba8bd56792560efe
|
||||
F ext/session/session_common.tcl fb91560b6dbd086010df8b3a137a452f1ac21a28
|
||||
F ext/session/sessionfault.test d7e6154a30e85622d0733b1a1e3c63e9b8b7004b
|
||||
F ext/session/sqlite3session.c 886827f10de75576baf9f9d860414fa155e1c8c1
|
||||
F ext/session/sqlite3session.h 8d3e00c0a2e323e6f47b1204ec9ff714ca3bee4a
|
||||
F ext/session/sqlite3session.c cf91fe0efb0728c219c8bc2b2174a49758fbd3f8
|
||||
F ext/session/sqlite3session.h 900d900bb6a827f84754fc252a05638e0f413a6e
|
||||
F ext/session/test_session.c e0f500ec5e20478afc2c7998133e8acea7ec5104
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
@ -923,7 +924,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 9c3a6e479988e96086bef00c79dbce508a14da0d
|
||||
R f502a856cffb82507c875b00a2fb9d4d
|
||||
P 54298ee5ed183d1f1c49524f25e8ae1407f3d4b5
|
||||
R 73cd0f1e5ce098769e9cee2c7d1f1ebc
|
||||
U dan
|
||||
Z 3fdb3d84abab55a6e9fe1eeceb839a7c
|
||||
Z 8a40e5171d2567a1ae6ca1b697973f9a
|
||||
|
@ -1 +1 @@
|
||||
54298ee5ed183d1f1c49524f25e8ae1407f3d4b5
|
||||
506a0d7a710e1ff2f367821e73f5080fcf63fbc5
|
Reference in New Issue
Block a user