@@ -56,7 +56,9 @@ static void sync_db(sqlite3 *db_primary, sqlite3 *db_backup){
5656 for (int i = 1 ; i <=max_frame ; i ++ ){
5757 char frame [4096 + 24 ];
5858 ensure (libsql_wal_get_frame (db_primary , i , frame , sizeof (frame )) == SQLITE_OK , "can't get frame: %s\n" , sqlite3_errmsg (db_primary ));
59- ensure (libsql_wal_insert_frame (db_backup , i , frame , sizeof (frame )) == SQLITE_OK , "can't inject frame: %s\n" , sqlite3_errmsg (db_backup ));
59+ int conflict ;
60+ ensure (libsql_wal_insert_frame (db_backup , i , frame , sizeof (frame ), & conflict ) == SQLITE_OK , "can't inject frame: %s\n" , sqlite3_errmsg (db_backup ));
61+ ensure (conflict == 0 , "conflict at frame %d\n" , i );
6062 }
6163 ensure (libsql_wal_insert_end (db_backup ) == SQLITE_OK , "can't end commit: %s\n" , sqlite3_errmsg (db_backup ));
6264}
@@ -110,7 +112,9 @@ void test_sync_by_parts() {
110112 in_commit = 1 ;
111113 ensure (libsql_wal_insert_begin (db_backup ) == SQLITE_OK , "can't begin commit: %s\n" , sqlite3_errmsg (db_backup ));
112114 }
113- ensure (libsql_wal_insert_frame (db_backup , i , frame , sizeof (frame )) == SQLITE_OK , "can't inject frame: %s\n" , sqlite3_errmsg (db_backup ));
115+ int conflict ;
116+ ensure (libsql_wal_insert_frame (db_backup , i , frame , sizeof (frame ), & conflict ) == SQLITE_OK , "can't inject frame: %s\n" , sqlite3_errmsg (db_backup ));
117+ ensure (conflict == 0 , "conflict at frame %d\n" , i );
114118 if (is_commit ) {
115119 ensure (libsql_wal_insert_end (db_backup ) == SQLITE_OK , "can't end commit: %s\n" , sqlite3_errmsg (db_backup ));
116120 in_commit = 0 ;
@@ -145,6 +149,44 @@ void test_sync_while_reading() {
145149 cmp_data (db_primary , db_backup );
146150}
147151
152+ // This test case writes to two different databases and then attempts to sync them to a third database.
153+ // Only the first database should be synced, the second database sync should return a conflict error
154+ void test_conflict () {
155+ sqlite3 * db1 , * db2 , * db_synced ;
156+ open_db ("test_conflict_1.db" , & db1 );
157+ open_db ("test_conflict_2.db" , & db2 );
158+ open_db ("test_conflict_synced.db" , & db_synced );
159+
160+ ensure (sqlite3_exec (db1 , "CREATE TABLE t (x)" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
161+ ensure (sqlite3_exec (db1 , "INSERT INTO t VALUES (randomblob(4 * 1024))" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
162+
163+ sync_db (db1 , db_synced );
164+
165+ ensure (sqlite3_exec (db2 , "CREATE TABLE t (x)" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
166+ ensure (sqlite3_exec (db2 , "INSERT INTO t VALUES (randomblob(4 * 1024))" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
167+
168+ unsigned int max_frame ;
169+ ensure (libsql_wal_frame_count (db2 , & max_frame ) == SQLITE_OK , "can't get frame count: %s\n" , sqlite3_errmsg (db2 ));
170+ ensure (libsql_wal_insert_begin (db_synced ) == SQLITE_OK , "can't begin commit: %s\n" , sqlite3_errmsg (db_synced ));
171+ // First 3 frames should not conflict.
172+ for (int i = 1 ; i <=3 ; i ++ ){
173+ char frame [4096 + 24 ];
174+ ensure (libsql_wal_get_frame (db2 , i , frame , sizeof (frame )) == SQLITE_OK , "can't get frame: %s\n" , sqlite3_errmsg (db2 ));
175+ int conflict ;
176+ ensure (libsql_wal_insert_frame (db_synced , i , frame , sizeof (frame ), & conflict ) == SQLITE_OK , "conflict detected: %s\n" , sqlite3_errmsg (db_synced ));
177+ ensure (conflict == 0 , "conflict at frame %d\n" , i );
178+ }
179+ // The rest should conflict.
180+ for (int i = 4 ; i <=max_frame ; i ++ ){
181+ char frame [4096 + 24 ];
182+ ensure (libsql_wal_get_frame (db2 , i , frame , sizeof (frame )) == SQLITE_OK , "can't get frame: %s\n" , sqlite3_errmsg (db2 ));
183+ int conflict ;
184+ ensure (libsql_wal_insert_frame (db_synced , i , frame , sizeof (frame ), & conflict ) == SQLITE_ERROR , "conflict not detected: %s\n" , sqlite3_errmsg (db_synced ));
185+ ensure (conflict == 1 , "no conflict at frame %d\n" , i );
186+ }
187+ ensure (libsql_wal_insert_end (db_synced ) == SQLITE_OK , "can't end commit: %s\n" , sqlite3_errmsg (db_synced ));
188+ }
189+
148190int main (int argc , char * argv [])
149191{
150192 test_huge_payload ();
@@ -156,5 +198,8 @@ int main(int argc, char *argv[])
156198 test_sync_while_reading ();
157199 printf ("============= OK test_sync_while_reading\n" );
158200
201+ test_conflict ();
202+ printf ("============= OK test_conflict\n" );
203+
159204 return 0 ;
160205}
0 commit comments