From 53e91a5e22172d57edc095dd89c85524860815f5 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 6 Oct 2023 19:01:43 +0000 Subject: [PATCH] Add tests for the sqlite3changegroup_schema() API. FossilOrigin-Name: 5dab481c101b1523b1cfde92678cbc654ea26d946bf29da372d71c1f89cbaf46 --- ext/session/sessionalter.test | 96 ++++++++++++++++++++++++ ext/session/sessionfault3.test | 59 +++++++++++++++ ext/session/sqlite3session.c | 13 +++- ext/session/test_session.c | 132 +++++++++++++++++++++++++++++++++ manifest | 17 +++-- manifest.uuid | 2 +- 6 files changed, 306 insertions(+), 13 deletions(-) create mode 100644 ext/session/sessionfault3.test diff --git a/ext/session/sessionalter.test b/ext/session/sessionalter.test index d81b43c841..fb64b26d26 100644 --- a/ext/session/sessionalter.test +++ b/ext/session/sessionalter.test @@ -99,9 +99,105 @@ do_iterator_test 2.4 {} { {DELETE t1 0 X..... {i 2 i 3 i 4 t abcd i 5 f 7.2} {}} } +#------------------------------------------------------------------------- +# Tests of the sqlite3changegroup_xxx() APIs. +# +reset_db +do_execsql_test 3.0 { + CREATE TABLE t1(x INTEGER PRIMARY KEY, y); + CREATE TABLE t2(x PRIMARY KEY, y); + INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6); + INSERT INTO t2 VALUES('one', 'two'), ('three', 'four'), ('five', 'six'); +} +db_save_and_close +foreach {tn sql1 at sql2} { + 1 { + INSERT INTO t1(x, y) VALUES(7, 8); + } { + ALTER TABLE t1 ADD COLUMN z DEFAULT 10; + } { + UPDATE t1 SET y=11 WHERE x=7; + } + 2 { + UPDATE t2 SET y='two.two' WHERE x='one'; + DELETE FROM t2 WHERE x='five'; + INSERT INTO t2(x, y) VALUES('seven', 'eight'); + } { + ALTER TABLE t2 ADD COLUMN z; + ALTER TABLE t2 ADD COLUMN zz; + } { + } + + 3 { + DELETE FROM t2 WHERE x='five'; + } { + ALTER TABLE t2 ADD COLUMN z DEFAULT 'xyz'; + } { + } + + 4 { + UPDATE t2 SET y='two.two' WHERE x='three'; + } { + ALTER TABLE t2 ADD COLUMN z; + } { + UPDATE t2 SET z='abc' WHERE x='one'; + } + + 5* { + UPDATE t2 SET y='two.two' WHERE x='three'; + } { + ALTER TABLE t2 ADD COLUMN z DEFAULT 'defu1'; + } { + } + + 6* { + INSERT INTO t2(x, y) VALUES('nine', 'ten'); + } { + ALTER TABLE t2 ADD COLUMN z; + ALTER TABLE t2 ADD COLUMN a DEFAULT 'eelve'; + ALTER TABLE t2 ADD COLUMN b DEFAULT x'1234abcd'; + ALTER TABLE t2 ADD COLUMN c DEFAULT 4.2; + ALTER TABLE t2 ADD COLUMN d DEFAULT NULL; + } { + } +} { + db_restore_and_reopen + + set C1 [changeset_from_sql $sql1] + execsql $at + set C2 [changeset_from_sql $sql2] + + sqlite3changegroup grp + grp schema db main + grp add $C1 + grp add $C2 + set T1 [grp output] + grp delete + + db_restore_and_reopen + execsql $at + set T2 [changeset_from_sql "$sql1 ; $sql2"] + + if {[string range $tn end end]!="*"} { + do_test 3.1.$tn.1 { changeset_to_list $T1 } [changeset_to_list $T2] + } else { + set tn [string range $tn 0 end-1] + } + + db_restore_and_reopen + proc xConflict {args} { return "REPLACE" } + sqlite3changeset_apply_v2 db $T1 xConflict + set S1 [scksum db main] + + db_restore_and_reopen + sqlite3changeset_apply_v2 db $T2 xConflict + set S2 [scksum db main] + + do_test 3.1.$tn.2 { set S1 } $S2 +} diff --git a/ext/session/sessionfault3.test b/ext/session/sessionfault3.test new file mode 100644 index 0000000000..af5a4cdb43 --- /dev/null +++ b/ext/session/sessionfault3.test @@ -0,0 +1,59 @@ +# 2016 October 6 +# +# 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. +# +#*********************************************************************** +# +# The focus of this file is testing 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 +ifcapable !session {finish_test; return} +set testprefix sessionfault3 + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, PRIMARY KEY(a)); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t1 VALUES('five', 'six'); +} + +set C1 [changeset_from_sql { + INSERT INTO t1 VALUES('seven', 'eight'); + UPDATE t1 SET b=6 WHERE a='five'; + DELETE FROM t1 WHERE a=1; +}] + +do_execsql_test 1.1 { + ALTER TABLE t1 ADD COLUMN d DEFAULT 123; + ALTER TABLE t1 ADD COLUMN e DEFAULT 'string'; +} + +set C2 [changeset_from_sql { + UPDATE t1 SET e='new value' WHERE a='seven'; + INSERT INTO t1 VALUES(0, 0, 0, 0); +}] + +do_faultsim_test 1 -faults oom* -prep { + sqlite3changegroup G +} -body { + G schema db main + G add $::C1 + G add $::C2 + G output + set {} {} +} -test { + catch { G delete } + faultsim_test_result {0 {}} {1 SQLITE_NOMEM} +} + +finish_test diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 1c291f51c0..4e15c3fcd7 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -1472,9 +1472,7 @@ static int sessionPrepareDfltStmt( } static int sessionUpdateChanges(sqlite3_session *pSession, SessionTable *pTab){ - sqlite3 *db = pSession->db; sqlite3_stmt *pStmt = 0; - int ii = 0; int rc = pSession->rc; rc = sessionPrepareDfltStmt(pSession->db, pTab, &pStmt); @@ -2289,6 +2287,7 @@ static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){ sessionFree(pSession, p); } } + sqlite3_finalize(pTab->pDfltStmt); sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */ sessionFree(pSession, pTab->apChange); sessionFree(pSession, pTab); @@ -5398,7 +5397,7 @@ struct sqlite3_changegroup { SessionTable *pList; /* List of tables in current patch */ sqlite3 *db; /* Configured by changegroup_schema() */ - const char *zDb; /* Configured by changegroup_schema() */ + char *zDb; /* Configured by changegroup_schema() */ }; /* @@ -5625,7 +5624,7 @@ static int sessionChangesetExtendRecord( if( op==SQLITE_INSERT || (op==SQLITE_DELETE && pGrp->bPatch==0) ){ /* Append the missing default column values to the record. */ sessionAppendBlob(pOut, aRec, nRec, &rc); - if( pTab->pDfltStmt==0 ){ + if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){ rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt); } for(ii=nCol; rc==SQLITE_OK && iinCol; ii++){ @@ -5752,6 +5751,11 @@ static int sessionChangesetToHash( if( pGrp->db ){ pTab->nCol = 0; rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb); + if( rc ){ + assert( pTab->azCol==0 ); + sqlite3_free(pTab); + break; + } } /* The new object must be linked on to the end of the list, not @@ -5985,6 +5989,7 @@ int sqlite3changegroup_output_strm( */ void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ if( pGrp ){ + sqlite3_free(pGrp->zDb); sessionDeleteTable(0, pGrp->pList); sqlite3_free(pGrp); } diff --git a/ext/session/test_session.c b/ext/session/test_session.c index 0836238b5d..df42884efc 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -1452,12 +1452,144 @@ static int SQLITE_TCLAPI test_sqlite3session_config( return TCL_OK; } +typedef struct TestChangegroup TestChangegroup; +struct TestChangegroup { + sqlite3_changegroup *pGrp; +}; + +/* +** Destructor for Tcl changegroup command object. +*/ +static void test_changegroup_del(void *clientData){ + TestChangegroup *pGrp = (TestChangegroup*)clientData; + sqlite3changegroup_delete(pGrp->pGrp); + ckfree(pGrp); +} + +/* +** Tclcmd: $changegroup schema DB DBNAME +** Tclcmd: $changegroup add CHANGESET +** Tclcmd: $changegroup output +** Tclcmd: $changegroup delete +*/ +static int SQLITE_TCLAPI test_changegroup_cmd( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + TestChangegroup *p = (TestChangegroup*)clientData; + static struct ChangegroupCmd { + const char *zSub; + int nArg; + const char *zMsg; + int iSub; + } aSub[] = { + { "schema", 2, "DB DBNAME", }, /* 0 */ + { "add", 1, "CHANGESET", }, /* 1 */ + { "output", 0, "", }, /* 2 */ + { "delete", 0, "", }, /* 3 */ + { 0 } + }; + int rc = TCL_OK; + int iSub = 0; + + if( objc<2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); + return TCL_ERROR; + } + rc = Tcl_GetIndexFromObjStruct(interp, + objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iSub + ); + if( rc!=TCL_OK ) return rc; + if( objc!=2+aSub[iSub].nArg ){ + Tcl_WrongNumArgs(interp, 2, objv, aSub[iSub].zMsg); + return TCL_ERROR; + } + + switch( iSub ){ + case 0: { /* schema */ + sqlite3 *db = 0; + const char *zDb = Tcl_GetString(objv[3]); + if( dbHandleFromObj(interp, objv[2], &db) ){ + return TCL_ERROR; + } + rc = sqlite3changegroup_schema(p->pGrp, db, zDb); + if( rc!=SQLITE_OK ) rc = test_session_error(interp, rc, 0); + break; + }; + + case 1: { /* add */ + int nByte = 0; + const u8 *aByte = Tcl_GetByteArrayFromObj(objv[2], &nByte); + rc = sqlite3changegroup_add(p->pGrp, nByte, (void*)aByte); + if( rc!=SQLITE_OK ) rc = test_session_error(interp, rc, 0); + break; + }; + + case 2: { /* output */ + int nByte = 0; + const u8 *aByte = 0; + rc = sqlite3changegroup_output(p->pGrp, &nByte, (void**)&aByte); + if( rc!=SQLITE_OK ){ + rc = test_session_error(interp, rc, 0); + }else{ + Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(aByte, nByte)); + } + sqlite3_free(aByte); + break; + }; + + default: { /* delete */ + assert( iSub==3 ); + Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); + break; + } + } + + return rc; +} + +/* +** Tclcmd: sqlite3changegroup CMD +*/ +static int SQLITE_TCLAPI test_sqlite3changegroup( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int rc; /* sqlite3changegroup_new() return code */ + TestChangegroup *p; /* New wrapper object */ + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "CMD"); + return TCL_ERROR; + } + + p = (TestChangegroup*)ckalloc(sizeof(TestChangegroup)); + memset(p, 0, sizeof(TestChangegroup)); + rc = sqlite3changegroup_new(&p->pGrp); + if( rc!=SQLITE_OK ){ + ckfree((char*)p); + return test_session_error(interp, rc, 0); + } + + Tcl_CreateObjCommand( + interp, Tcl_GetString(objv[1]), test_changegroup_cmd, (ClientData)p, + test_changegroup_del + ); + Tcl_SetObjResult(interp, objv[1]); + return TCL_OK; +} + int TestSession_Init(Tcl_Interp *interp){ struct Cmd { const char *zCmd; Tcl_ObjCmdProc *xProc; } aCmd[] = { { "sqlite3session", test_sqlite3session }, + { "sqlite3changegroup", test_sqlite3changegroup }, { "sqlite3session_foreach", test_sqlite3session_foreach }, { "sqlite3changeset_invert", test_sqlite3changeset_invert }, { "sqlite3changeset_concat", test_sqlite3changeset_concat }, diff --git a/manifest b/manifest index cf27c7fb81..3f9d9dded8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\ssqlite3changegroup_schema()\sAPI.\sTo\sallow\schangegroups\sto\shandle\sdifferences\sin\sschema\screated\sby\sALTER\sTABLE\sADD\sCOLUMN. -D 2023-10-05T19:09:23.510 +C Add\stests\sfor\sthe\ssqlite3changegroup_schema()\sAPI. +D 2023-10-06T19:01:43.150 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -529,12 +529,13 @@ F ext/session/sessionG.test 3efe388282d641b65485b5462e67851002cd91a282dc95b685d0 F ext/session/sessionH.test 71bbff6b1abb2c4ac62b84dee53273c37e0b21e5fde3aed80929403e091ef859 F ext/session/session_common.tcl e5598096425486b363718e2cda48ee85d660c96b4f8ea9d9d7a4c3ef514769da F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3 -F ext/session/sessionalter.test 2623023075c51707026a90b9b59674e88c6f467098219d8d71f9a6320d122c61 +F ext/session/sessionalter.test 29d77c44087263c63d69be69219734d636ea68635307500d5b0f07a056e4d432 F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b85419035bc04b45ee F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec F ext/session/sessionfault.test 573bf027fb870d57bd4e7cf50822a3e4b17b2b923407438747aaa918dec57a09 F ext/session/sessionfault2.test b0d6a7c1d7398a7e800d84657404909c7d385965ea8576dc79ed344c46fbf41c +F ext/session/sessionfault3.test 7c7547202775de268f3fe6f074c4d0d165151829710b4e64f90d4a01645ba9e7 F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25 F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09 F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7 @@ -544,9 +545,9 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795 F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc -F ext/session/sqlite3session.c 8a0886dc8772c00ccbfe10012e8d21175a96ee18428a58fae9be81d924b89d03 +F ext/session/sqlite3session.c fdf5d63f7e2f722938ce4aee18d472a8fae90f134b63d3f3a3c1c69185d6ef62 F ext/session/sqlite3session.h 4d1f69f1d8bfd4798e8f6431de301d17bb2e4097de2f77ca4dad494bb6c60dc0 -F ext/session/test_session.c 5285482f83cd92b4c1fe12fcf88210566a18312f4f2aa110f6399dae46aeccbb +F ext/session/test_session.c 0b4bc954e5e411baa723e52abd46380ca428797dff39ed62c610001777a2b70f F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb @@ -2124,8 +2125,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a3f435eccf3a2aa11cb7420e94af5efcdfa04e9c169c5aaf61fa5cdcb165ceef -R a796b1e127975d7f78d17f701882d2f3 +P 309deee2dd8dd07623fce79f6bb62d5279d140dd0be3b34bc42af20b0507726b +R 33722f2202fca685ef72d8b590a6e7d1 U dan -Z afe7ef1533b48179b0f6fa3866dc9cb3 +Z 92cf09eb69840306d89500d5cc947e40 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1d23b0122d..fa49b95b37 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -309deee2dd8dd07623fce79f6bb62d5279d140dd0be3b34bc42af20b0507726b \ No newline at end of file +5dab481c101b1523b1cfde92678cbc654ea26d946bf29da372d71c1f89cbaf46 \ No newline at end of file