@@ -1740,7 +1740,6 @@ bool do_test_dbutils (void) {
17401740 "CREATE TABLE IF NOT EXISTS integer_pk (id INTEGER PRIMARY KEY NOT NULL, value);"
17411741 "CREATE TABLE IF NOT EXISTS int_pk (id INT PRIMARY KEY NOT NULL, value);"
17421742 "CREATE TABLE IF NOT EXISTS \"quoted table name 🚀\" (\"pk quoted col 1\" TEXT NOT NULL, \"pk quoted col 2\" TEXT NOT NULL, \"non pk quoted col 1\", \"non pk quoted col 2\", PRIMARY KEY (\"pk quoted col 1\", \"pk quoted col 2\"));" ;
1743- ;
17441743
17451744 rc = sqlite3_exec (db , sql , NULL , NULL , NULL );
17461745 if (rc != SQLITE_OK ) goto finalize ;
@@ -2031,6 +2030,35 @@ bool do_test_string_replace_prefix(void) {
20312030 return true;
20322031}
20332032
2033+ bool do_test_many_columns (int ncols , sqlite3 * db ) {
2034+ char sql_create [10000 ];
2035+ int pos = 0 ;
2036+ pos += snprintf (sql_create + pos , sizeof (sql_create )- pos , "CREATE TABLE IF NOT EXISTS test_many_columns (id TEXT PRIMARY KEY NOT NULL" );
2037+ for (int i = 1 ; i < ncols ; i ++ ) {
2038+ pos += snprintf (sql_create + pos , sizeof (sql_create )- pos , ", col%d TEXT" , i );
2039+ }
2040+ pos += snprintf (sql_create + pos , sizeof (sql_create )- pos , ");" );
2041+
2042+ int rc = sqlite3_exec (db , sql_create , NULL , NULL , NULL );
2043+ if (rc != SQLITE_OK ) return false;
2044+
2045+ char * sql = "SELECT cloudsync_init('test_many_columns', 'cls', 1);" ;
2046+ rc = sqlite3_exec (db , sql , NULL , NULL , NULL );
2047+ if (rc != SQLITE_OK ) return false;
2048+
2049+ sql = sqlite3_mprintf ("INSERT INTO test_many_columns (id, col1, col%d) VALUES ('test-id-1', 'original1', 'original%d');" , ncols - 1 , ncols - 1 );
2050+ rc = sqlite3_exec (db , sql , NULL , NULL , NULL );
2051+ sqlite3_free (sql );
2052+ if (rc != SQLITE_OK ) return false;
2053+
2054+ sql = sqlite3_mprintf ("UPDATE test_many_columns SET col1 = 'updated1', col%d = 'updated%d' WHERE id = 'test-id-1';" , ncols - 1 , ncols - 1 );
2055+ rc = sqlite3_exec (db , sql , NULL , NULL , NULL );
2056+ sqlite3_free (sql );
2057+ if (rc != SQLITE_OK ) return false;
2058+
2059+ return true;
2060+ }
2061+
20342062// MARK: -
20352063
20362064bool do_compare_queries (sqlite3 * db1 , const char * sql1 , sqlite3 * db2 , const char * sql2 , int col_to_skip , int col_tombstone , bool display_column ) {
@@ -2874,6 +2902,127 @@ bool do_test_merge_alter_schema_2 (int nclients, bool print_result, bool cleanup
28742902 return result ;
28752903}
28762904
2905+ bool do_test_merge_two_tables (int nclients , bool print_result , bool cleanup_databases ) {
2906+ sqlite3 * db [MAX_SIMULATED_CLIENTS ] = {NULL };
2907+ bool result = false;
2908+ int rc = SQLITE_OK ;
2909+ int table_mask = TEST_PRIKEYS | TEST_NOCOLS ;
2910+
2911+ memset (db , 0 , sizeof (sqlite3 * ) * MAX_SIMULATED_CLIENTS );
2912+ if (nclients >= MAX_SIMULATED_CLIENTS ) {
2913+ nclients = MAX_SIMULATED_CLIENTS ;
2914+ printf ("Number of test merge reduced to %d clients\n" , MAX_SIMULATED_CLIENTS );
2915+ } else if (nclients < 2 ) {
2916+ nclients = 2 ;
2917+ printf ("Number of test merge increased to %d clients\n" , 2 );
2918+ }
2919+
2920+ // create databases and tables
2921+ time_t timestamp = time (NULL );
2922+ int saved_counter = test_counter ;
2923+ for (int i = 0 ; i < nclients ; ++ i ) {
2924+ db [i ] = do_create_database_file (i , timestamp , test_counter ++ );
2925+ if (db [i ] == false) return false;
2926+
2927+ if (do_create_tables (table_mask , db [i ]) == false) {
2928+ return false;
2929+ }
2930+
2931+ if (do_augment_tables (table_mask , db [i ], table_algo_crdt_cls ) == false) {
2932+ return false;
2933+ }
2934+ }
2935+
2936+ // perform transactions on both tables in client 0
2937+ rc = sqlite3_exec (db [0 ], "BEGIN TRANSACTION;" , NULL , NULL , NULL );
2938+ if (rc != SQLITE_OK ) goto finalize ;
2939+
2940+ // insert data into both tables in a single transaction
2941+ char * sql = sqlite3_mprintf ("INSERT INTO \"%w\" (first_name, \"" CUSTOMERS_TABLE_COLUMN_LASTNAME "\", age, note, stamp) VALUES ('john', 'doe', 30, 'test note', 'stamp1');" , CUSTOMERS_TABLE );
2942+ rc = sqlite3_exec (db [0 ], sql , NULL , NULL , NULL );
2943+ sqlite3_free (sql );
2944+ if (rc != SQLITE_OK ) goto finalize ;
2945+
2946+ sql = sqlite3_mprintf ("INSERT INTO \"%w\" (first_name, \"" CUSTOMERS_TABLE_COLUMN_LASTNAME "\") VALUES ('jane', 'smith');" , CUSTOMERS_NOCOLS_TABLE );
2947+ rc = sqlite3_exec (db [0 ], sql , NULL , NULL , NULL );
2948+ sqlite3_free (sql );
2949+ if (rc != SQLITE_OK ) goto finalize ;
2950+
2951+ rc = sqlite3_exec (db [0 ], "COMMIT;" , NULL , NULL , NULL );
2952+ if (rc != SQLITE_OK ) goto finalize ;
2953+
2954+ // perform different transactions on both tables in client 1
2955+ rc = sqlite3_exec (db [1 ], "BEGIN TRANSACTION;" , NULL , NULL , NULL );
2956+ if (rc != SQLITE_OK ) goto finalize ;
2957+
2958+ sql = sqlite3_mprintf ("INSERT INTO \"%w\" (first_name, \"" CUSTOMERS_TABLE_COLUMN_LASTNAME "\", age, note, stamp) VALUES ('alice', 'jones', 25, 'another note', 'stamp2');" , CUSTOMERS_TABLE );
2959+ rc = sqlite3_exec (db [1 ], sql , NULL , NULL , NULL );
2960+ sqlite3_free (sql );
2961+ if (rc != SQLITE_OK ) goto finalize ;
2962+
2963+ sql = sqlite3_mprintf ("INSERT INTO \"%w\" (first_name, \"" CUSTOMERS_TABLE_COLUMN_LASTNAME "\") VALUES ('bob', 'wilson');" , CUSTOMERS_NOCOLS_TABLE );
2964+ rc = sqlite3_exec (db [1 ], sql , NULL , NULL , NULL );
2965+ sqlite3_free (sql );
2966+ if (rc != SQLITE_OK ) goto finalize ;
2967+
2968+ rc = sqlite3_exec (db [1 ], "COMMIT;" , NULL , NULL , NULL );
2969+ if (rc != SQLITE_OK ) goto finalize ;
2970+
2971+ // merge changes between the two clients
2972+ if (do_merge (db , nclients , false) == false) {
2973+ goto finalize ;
2974+ }
2975+
2976+ // verify that both databases have the same content for both tables
2977+ for (int i = 1 ; i < nclients ; ++ i ) {
2978+ // compare customers table
2979+ sql = sqlite3_mprintf ("SELECT * FROM \"%w\" ORDER BY first_name, \"" CUSTOMERS_TABLE_COLUMN_LASTNAME "\";" , CUSTOMERS_TABLE );
2980+ bool comparison_result = do_compare_queries (db [0 ], sql , db [i ], sql , -1 , -1 , print_result );
2981+ sqlite3_free (sql );
2982+ if (comparison_result == false) goto finalize ;
2983+
2984+ // compare customers_nocols table
2985+ const char * nocols_sql = "SELECT * FROM \"" CUSTOMERS_NOCOLS_TABLE "\" ORDER BY first_name, \"" CUSTOMERS_TABLE_COLUMN_LASTNAME "\";" ;
2986+ if (do_compare_queries (db [0 ], nocols_sql , db [i ], nocols_sql , -1 , -1 , print_result ) == false) goto finalize ;
2987+ }
2988+
2989+ if (print_result ) {
2990+ printf ("\n-> " CUSTOMERS_TABLE "\n" );
2991+ sql = sqlite3_mprintf ("SELECT * FROM \"%w\" ORDER BY first_name, \"" CUSTOMERS_TABLE_COLUMN_LASTNAME "\";" , CUSTOMERS_TABLE );
2992+ do_query (db [0 ], sql , query_table );
2993+ sqlite3_free (sql );
2994+
2995+ printf ("\n-> \"" CUSTOMERS_NOCOLS_TABLE "\"\n" );
2996+ do_query (db [0 ], "SELECT * FROM \"" CUSTOMERS_NOCOLS_TABLE "\" ORDER BY first_name, \"" CUSTOMERS_TABLE_COLUMN_LASTNAME "\";" , query_table );
2997+ }
2998+
2999+ result = true;
3000+ rc = SQLITE_OK ;
3001+
3002+ finalize :
3003+ for (int i = 0 ; i < nclients ; ++ i ) {
3004+ if (rc != SQLITE_OK && db [i ] && (sqlite3_errcode (db [i ]) != SQLITE_OK )) printf ("do_test_merge_two_tables error: %s\n" , sqlite3_errmsg (db [i ]));
3005+ if (db [i ]) {
3006+ if (sqlite3_get_autocommit (db [i ]) == 0 ) {
3007+ result = false;
3008+ printf ("do_test_merge_two_tables error: db %d is in transaction\n" , i );
3009+ }
3010+
3011+ int counter = close_db_v2 (db [i ]);
3012+ if (counter > 0 ) {
3013+ result = false;
3014+ printf ("do_test_merge_two_tables error: db %d has %d unterminated statements\n" , i , counter );
3015+ }
3016+ }
3017+ if (cleanup_databases ) {
3018+ char buf [256 ];
3019+ do_build_database_path (buf , i , timestamp , saved_counter ++ );
3020+ file_delete (buf );
3021+ }
3022+ }
3023+ return result ;
3024+ }
3025+
28773026bool do_test_prikey (int nclients , bool print_result , bool cleanup_databases ) {
28783027 sqlite3 * db [MAX_SIMULATED_CLIENTS ] = {NULL };
28793028 bool result = false;
@@ -3455,7 +3604,8 @@ int main(int argc, const char * argv[]) {
34553604 result += test_report ("Functions Test:" , do_test_functions (db , print_result ));
34563605 result += test_report ("Functions Test (Int):" , do_test_internal_functions ());
34573606 result += test_report ("String Func Test:" , do_test_string_replace_prefix ());
3458-
3607+ result += test_report ("Test Many Columns:" , do_test_many_columns (600 , db ));
3608+
34593609 // close local database
34603610 db = close_db (db );
34613611
@@ -3467,6 +3617,7 @@ int main(int argc, const char * argv[]) {
34673617 result += test_report ("Merge Test 5:" , do_test_merge_5 (2 , print_result , cleanup_databases , false));
34683618 result += test_report ("Merge Alter Schema 1:" , do_test_merge_alter_schema_1 (2 , print_result , cleanup_databases , false));
34693619 result += test_report ("Merge Alter Schema 2:" , do_test_merge_alter_schema_2 (2 , print_result , cleanup_databases , false));
3620+ result += test_report ("Merge Two Tables Test:" , do_test_merge_two_tables (2 , print_result , cleanup_databases ));
34703621 result += test_report ("PriKey NULL Test:" , do_test_prikey (2 , print_result , cleanup_databases ));
34713622 result += test_report ("Test Double Init:" , do_test_double_init (2 , cleanup_databases ));
34723623
0 commit comments