]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add tests for the sqlite3changegroup_schema() API.
authordan <Dan Kennedy>
Fri, 6 Oct 2023 19:01:43 +0000 (19:01 +0000)
committerdan <Dan Kennedy>
Fri, 6 Oct 2023 19:01:43 +0000 (19:01 +0000)
FossilOrigin-Name: 5dab481c101b1523b1cfde92678cbc654ea26d946bf29da372d71c1f89cbaf46

ext/session/sessionalter.test
ext/session/sessionfault3.test [new file with mode: 0644]
ext/session/sqlite3session.c
ext/session/test_session.c
manifest
manifest.uuid

index d81b43c8417c0881e26ab5b158e33851f22b1943..fb64b26d260626950d2809cbb4769af623a5136b 100644 (file)
@@ -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 (file)
index 0000000..af5a4cd
--- /dev/null
@@ -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
index 1c291f51c0171519ed294aa761eed0b154268de3..4e15c3fcd721c6e24108fa6e01bb90fa2ad20008 100644 (file)
@@ -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 && ii<pTab->nCol; 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);
   }
index 0836238b5d320f62a5d21e0905a2b5ceb57b6f37..df42884efcdf155c4156bf520a3ee821bf73e1ae 100644 (file)
@@ -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 },
index cf27c7fb81a2ff3f31227a3e553ba4ae1b6b76e2..3f9d9dded8e08053a49312ac74f71d804f2764ed 100644 (file)
--- 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.
index 1d23b0122d48a2d42c202dfb99d1f2d6e161d9eb..fa49b95b37618697af29af2c240ab72204c3e69e 100644 (file)
@@ -1 +1 @@
-309deee2dd8dd07623fce79f6bb62d5279d140dd0be3b34bc42af20b0507726b
\ No newline at end of file
+5dab481c101b1523b1cfde92678cbc654ea26d946bf29da372d71c1f89cbaf46
\ No newline at end of file