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 */
|
sqlite3 *db, /* Database connection */
|
||||||
const char *zDb, /* Name of attached database (e.g. "main") */
|
const char *zDb, /* Name of attached database (e.g. "main") */
|
||||||
const char *zThis, /* Table name */
|
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 **pzTab, /* OUT: Copy of zThis */
|
||||||
const char ***pazCol, /* OUT: Array of column names for table */
|
const char ***pazCol, /* OUT: Array of column names for table */
|
||||||
u8 **pabPK /* OUT: Array of booleans - true for PK col */
|
u8 **pabPK /* OUT: Array of booleans - true for PK col */
|
||||||
@ -577,9 +577,6 @@ static int sessionTableInfo(
|
|||||||
}
|
}
|
||||||
rc = sqlite3_reset(pStmt);
|
rc = sqlite3_reset(pStmt);
|
||||||
|
|
||||||
if( nDbCol!=nCol ){
|
|
||||||
rc = SQLITE_SCHEMA;
|
|
||||||
}
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
|
nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
|
||||||
pAlloc = sqlite3_malloc(nByte);
|
pAlloc = sqlite3_malloc(nByte);
|
||||||
@ -589,9 +586,9 @@ static int sessionTableInfo(
|
|||||||
}
|
}
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
azCol = (char **)pAlloc;
|
azCol = (char **)pAlloc;
|
||||||
pAlloc = (u8 *)&azCol[nCol];
|
pAlloc = (u8 *)&azCol[nDbCol];
|
||||||
abPK = (u8 *)pAlloc;
|
abPK = (u8 *)pAlloc;
|
||||||
pAlloc = &abPK[nCol];
|
pAlloc = &abPK[nDbCol];
|
||||||
if( pzTab ){
|
if( pzTab ){
|
||||||
memcpy(pAlloc, zThis, nThis+1);
|
memcpy(pAlloc, zThis, nThis+1);
|
||||||
*pzTab = (char *)pAlloc;
|
*pzTab = (char *)pAlloc;
|
||||||
@ -619,9 +616,11 @@ static int sessionTableInfo(
|
|||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
*pazCol = (const char **)azCol;
|
*pazCol = (const char **)azCol;
|
||||||
*pabPK = abPK;
|
*pabPK = abPK;
|
||||||
|
*pnCol = nDbCol;
|
||||||
}else{
|
}else{
|
||||||
*pazCol = 0;
|
*pazCol = 0;
|
||||||
*pabPK = 0;
|
*pabPK = 0;
|
||||||
|
*pnCol = 0;
|
||||||
if( pzTab ) *pzTab = 0;
|
if( pzTab ) *pzTab = 0;
|
||||||
sqlite3_free(azCol);
|
sqlite3_free(azCol);
|
||||||
}
|
}
|
||||||
@ -648,11 +647,13 @@ static int sessionTableInfo(
|
|||||||
static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
|
static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
|
||||||
if( pTab->nCol==0 ){
|
if( pTab->nCol==0 ){
|
||||||
assert( pTab->azCol==0 || pTab->abPK==0 );
|
assert( pTab->azCol==0 || pTab->abPK==0 );
|
||||||
pTab->nCol = sqlite3_preupdate_count(pSession->db);
|
|
||||||
pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
|
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;
|
pSession->rc = SQLITE_SCHEMA;
|
||||||
}
|
}
|
||||||
return pSession->rc;
|
return pSession->rc;
|
||||||
@ -2402,6 +2403,7 @@ int sqlite3changeset_apply(
|
|||||||
),
|
),
|
||||||
void *pCtx /* First argument passed to xConflict */
|
void *pCtx /* First argument passed to xConflict */
|
||||||
){
|
){
|
||||||
|
int schemaMismatch = 0;
|
||||||
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
||||||
int rc; /* Return code */
|
int rc; /* Return code */
|
||||||
const char *zTab = 0; /* Name of current table */
|
const char *zTab = 0; /* Name of current table */
|
||||||
@ -2420,9 +2422,13 @@ int sqlite3changeset_apply(
|
|||||||
int bReplace = 0;
|
int bReplace = 0;
|
||||||
int bRetry = 0;
|
int bRetry = 0;
|
||||||
const char *zNew;
|
const char *zNew;
|
||||||
|
|
||||||
sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
|
sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
|
||||||
|
|
||||||
if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
|
if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
|
||||||
|
u8 *abPK;
|
||||||
|
|
||||||
|
schemaMismatch = 0;
|
||||||
sqlite3_free(sApply.azCol);
|
sqlite3_free(sApply.azCol);
|
||||||
sqlite3_finalize(sApply.pDelete);
|
sqlite3_finalize(sApply.pDelete);
|
||||||
sqlite3_finalize(sApply.pUpdate);
|
sqlite3_finalize(sApply.pUpdate);
|
||||||
@ -2430,23 +2436,47 @@ int sqlite3changeset_apply(
|
|||||||
sqlite3_finalize(sApply.pSelect);
|
sqlite3_finalize(sApply.pSelect);
|
||||||
memset(&sApply, 0, sizeof(sApply));
|
memset(&sApply, 0, sizeof(sApply));
|
||||||
sApply.db = db;
|
sApply.db = db;
|
||||||
sApply.nCol = nCol;
|
|
||||||
|
|
||||||
|
sqlite3changeset_pk(pIter, &abPK, 0);
|
||||||
rc = sessionTableInfo(
|
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
|
if( sApply.nCol==0 ){
|
||||||
|| (rc = sessionSelectRow(db, zTab, &sApply))
|
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 = sessionUpdateRow(db, zTab, &sApply))
|
||||||
|| (rc = sessionDeleteRow(db, zTab, &sApply))
|
|| (rc = sessionDeleteRow(db, zTab, &sApply))
|
||||||
|| (rc = sessionInsertRow(db, zTab, &sApply))
|
|| (rc = sessionInsertRow(db, zTab, &sApply))
|
||||||
){
|
){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
nTab = strlen(zTab);
|
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);
|
rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, &bRetry);
|
||||||
|
|
||||||
if( rc==SQLITE_OK && 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
|
** 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
|
** 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.
|
** to the database when the session object is created.
|
||||||
*/
|
*/
|
||||||
int sqlite3session_create(
|
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.
|
C Fix\shandling\sof\sschema\smismatches\sin\ssqlite3session.c\sso\sthat\sit\smatches\sthe\sdocs\sin\ssqlite3session.h.
|
||||||
D 2011-03-24T11:22:59
|
D 2011-03-24T16:04:55
|
||||||
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
|
||||||
@ -101,10 +101,11 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
|||||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||||
F ext/session/session1.test b2da15b9d727d7f4e5fe95599b32b92d93b5a970
|
F ext/session/session1.test b2da15b9d727d7f4e5fe95599b32b92d93b5a970
|
||||||
F ext/session/session2.test 8da094318ac88953478c43d0bfb0aa723ee0e379
|
F ext/session/session2.test 8da094318ac88953478c43d0bfb0aa723ee0e379
|
||||||
|
F ext/session/session3.test b8b9ff7efcb19234892c406dba8bd56792560efe
|
||||||
F ext/session/session_common.tcl fb91560b6dbd086010df8b3a137a452f1ac21a28
|
F ext/session/session_common.tcl fb91560b6dbd086010df8b3a137a452f1ac21a28
|
||||||
F ext/session/sessionfault.test d7e6154a30e85622d0733b1a1e3c63e9b8b7004b
|
F ext/session/sessionfault.test d7e6154a30e85622d0733b1a1e3c63e9b8b7004b
|
||||||
F ext/session/sqlite3session.c 886827f10de75576baf9f9d860414fa155e1c8c1
|
F ext/session/sqlite3session.c cf91fe0efb0728c219c8bc2b2174a49758fbd3f8
|
||||||
F ext/session/sqlite3session.h 8d3e00c0a2e323e6f47b1204ec9ff714ca3bee4a
|
F ext/session/sqlite3session.h 900d900bb6a827f84754fc252a05638e0f413a6e
|
||||||
F ext/session/test_session.c e0f500ec5e20478afc2c7998133e8acea7ec5104
|
F ext/session/test_session.c e0f500ec5e20478afc2c7998133e8acea7ec5104
|
||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||||
@ -923,7 +924,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 9c3a6e479988e96086bef00c79dbce508a14da0d
|
P 54298ee5ed183d1f1c49524f25e8ae1407f3d4b5
|
||||||
R f502a856cffb82507c875b00a2fb9d4d
|
R 73cd0f1e5ce098769e9cee2c7d1f1ebc
|
||||||
U dan
|
U dan
|
||||||
Z 3fdb3d84abab55a6e9fe1eeceb839a7c
|
Z 8a40e5171d2567a1ae6ca1b697973f9a
|
||||||
|
@ -1 +1 @@
|
|||||||
54298ee5ed183d1f1c49524f25e8ae1407f3d4b5
|
506a0d7a710e1ff2f367821e73f5080fcf63fbc5
|
Reference in New Issue
Block a user