@@ -391,18 +391,6 @@ db_int64 cloudsync_dbversion_next (cloudsync_context *data, db_int64 merging_ver
391391 return result ;
392392}
393393
394- // MARK: -
395-
396- void * cloudsync_get_auxdata (sqlite3_context * context ) {
397- cloudsync_context * data = (context ) ? (cloudsync_context * )sqlite3_user_data (context ) : NULL ;
398- return (data ) ? data -> aux_data : NULL ;
399- }
400-
401- void cloudsync_set_auxdata (sqlite3_context * context , void * xdata ) {
402- cloudsync_context * data = (context ) ? (cloudsync_context * )sqlite3_user_data (context ) : NULL ;
403- if (data ) data -> aux_data = xdata ;
404- }
405-
406394// MARK: - PK Context -
407395
408396char * cloudsync_pk_context_tbl (cloudsync_pk_decode_bind_context * ctx , int64_t * tbl_len ) {
@@ -532,7 +520,13 @@ int cloudsync_set_error (cloudsync_context *data, const char *err_user, int err_
532520 if (err_user == NULL ) {
533521 snprintf (data -> errmsg , sizeof (data -> errmsg ), "%s" , database_errmsg (db ));
534522 } else {
535- snprintf (data -> errmsg , sizeof (data -> errmsg ), "%s (%s)" , err_user , database_errmsg (db ));
523+ const char * db_error = database_errmsg (db );
524+ int rc = database_errcode (db );
525+ if (rc == DBRES_OK ) {
526+ snprintf (data -> errmsg , sizeof (data -> errmsg ), "%s" , err_user );
527+ } else {
528+ snprintf (data -> errmsg , sizeof (data -> errmsg ), "%s (%s)" , err_user , db_error );
529+ }
536530 }
537531
538532 return err_code ;
@@ -548,6 +542,12 @@ const char *cloudsync_errmsg (cloudsync_context *data) {
548542
549543// MARK: - Table Utils -
550544
545+ void table_pknames_free (char * * names , int nrows ) {
546+ if (!names ) return ;
547+ for (int i = 0 ; i < nrows ; ++ i ) {dbmem_free (names [i ]);}
548+ dbmem_free (names );
549+ }
550+
551551char * table_build_values_sql (db_t * db , cloudsync_table_context * table ) {
552552 char * sql = NULL ;
553553
@@ -726,8 +726,8 @@ void table_free (cloudsync_table_context *table) {
726726 }
727727 }
728728
729- if (table -> pk_name ) sqlite3_free_table (table -> pk_name );
730729 if (table -> name ) cloudsync_memory_free (table -> name );
730+ if (table -> pk_name ) table_pknames_free (table -> pk_name , table -> npks );
731731 if (table -> meta_pkexists_stmt ) database_finalize (table -> meta_pkexists_stmt );
732732 if (table -> meta_sentinel_update_stmt ) database_finalize (table -> meta_sentinel_update_stmt );
733733 if (table -> meta_sentinel_insert_stmt ) database_finalize (table -> meta_sentinel_insert_stmt );
@@ -1124,8 +1124,7 @@ char **table_pknames (cloudsync_table_context *table) {
11241124}
11251125
11261126void table_set_pknames (cloudsync_table_context * table , char * * pknames ) {
1127- // TODO: fix me
1128- if (table -> pk_name ) sqlite3_free_table (table -> pk_name );
1127+ table_pknames_free (table -> pk_name , table -> npks );
11291128 table -> pk_name = pknames ;
11301129}
11311130
@@ -1621,7 +1620,66 @@ void cloudsync_rollback_hook (void *ctx) {
16211620 data -> seq = 0 ;
16221621}
16231622
1624- int cloudsync_finalize_alter (sqlite3_context * context , cloudsync_context * data , cloudsync_table_context * table ) {
1623+ int cloudsync_begin_alter (cloudsync_context * data , const char * table_name ) {
1624+ db_t * db = data -> db ;
1625+
1626+ // init cloudsync_settings
1627+ if (cloudsync_context_init (data , db , NULL ) == NULL ) {
1628+ return cloudsync_set_error (data , "Unable to initialize cloudsync context" , SQLITE_MISUSE );
1629+ }
1630+
1631+ // lookup table
1632+ cloudsync_table_context * table = table_lookup (data , table_name );
1633+ if (!table ) {
1634+ char buffer [1024 ];
1635+ snprintf (buffer , sizeof (buffer ), "Unable to find table %s" , table_name );
1636+ return cloudsync_set_error (data , buffer , SQLITE_MISUSE );
1637+ }
1638+
1639+ // create a savepoint to manage the alter operations as a transaction
1640+ int rc = database_exec (db , "SAVEPOINT cloudsync_alter;" );
1641+ if (rc != SQLITE_OK ) {
1642+ return cloudsync_set_error (data , "Unable to create cloudsync_begin_alter savepoint" , SQLITE_MISUSE );
1643+ }
1644+
1645+ // retrieve primary key(s)
1646+ char * * names = NULL ;
1647+ int nrows = 0 ;
1648+ rc = database_pk_names (db , table_name , & names , & nrows );
1649+ if (rc != DBRES_OK ) {
1650+ char buffer [1024 ];
1651+ snprintf (buffer , sizeof (buffer ), "Unable to get primary keys for table %s" , table_name );
1652+ cloudsync_set_error (data , buffer , SQLITE_MISUSE );
1653+ goto rollback_begin_alter ;
1654+ }
1655+
1656+ // sanity check the number of primary keys
1657+ if (nrows != table_count_pks (table )) {
1658+ char buffer [1024 ];
1659+ snprintf (buffer , sizeof (buffer ), "Number of primary keys for table %s changed before ALTER" , table_name );
1660+ cloudsync_set_error (data , buffer , SQLITE_MISUSE );
1661+ goto rollback_begin_alter ;
1662+ }
1663+
1664+ // drop original triggers
1665+ dbutils_delete_triggers (db , table_name );
1666+ if (rc != SQLITE_OK ) {
1667+ char buffer [1024 ];
1668+ snprintf (buffer , sizeof (buffer ), "Unable to delete triggers for table %s in cloudsync_begin_alter." , table_name );
1669+ cloudsync_set_error (data , buffer , SQLITE_ERROR );
1670+ goto rollback_begin_alter ;
1671+ }
1672+
1673+ table_set_pknames (table , names );
1674+ return DBRES_OK ;
1675+
1676+ rollback_begin_alter :
1677+ database_exec (db , "ROLLBACK TO cloudsync_alter; RELEASE cloudsync_alter;" );
1678+ if (names ) table_pknames_free (names , nrows );
1679+ return rc ;
1680+ }
1681+
1682+ int cloudsync_finalize_alter (cloudsync_context * data , cloudsync_table_context * table ) {
16251683 // check if dbversion needed to be updated
16261684 cloudsync_dbversion_check_uptodate (data );
16271685
@@ -1640,24 +1698,6 @@ int cloudsync_finalize_alter (sqlite3_context *context, cloudsync_context *data,
16401698 goto finalize ;
16411699 }
16421700
1643- /*
1644- char *errmsg = NULL;
1645- char **result = NULL;
1646- int nrows, ncols;
1647- char *sql = cloudsync_memory_mprintf("SELECT name FROM pragma_table_info('%q') WHERE pk>0 ORDER BY pk;", table->name);
1648-
1649- sqlite3 *db = data->db;
1650- int rc = sqlite3_get_table(db, sql, &result, &nrows, &ncols, NULL);
1651- cloudsync_memory_free(sql);
1652- if (rc != SQLITE_OK) {
1653- DEBUG_SQLITE_ERROR(rc, "cloudsync_finalize_alter", db);
1654- goto finalize;
1655- } else if (errmsg || ncols != 1) {
1656- rc = SQLITE_MISUSE;
1657- goto finalize;
1658- }
1659- */
1660-
16611701 // check if there are differences
16621702 bool pk_diff = (nrows != table -> npks );
16631703 if (!pk_diff ) {
@@ -1669,20 +1709,6 @@ int cloudsync_finalize_alter (sqlite3_context *context, cloudsync_context *data,
16691709 }
16701710 }
16711711
1672- /*
1673- bool pk_diff = false;
1674- if (nrows != table->npks) {
1675- pk_diff = true;
1676- } else {
1677- for (int i=0; i<nrows; ++i) {
1678- if (strcmp(table->pk_name[i], result[i]) != 0) {
1679- pk_diff = true;
1680- break;
1681- }
1682- }
1683- }
1684- */
1685-
16861712 // TODO: FIX SQL
16871713 if (pk_diff ) {
16881714 // drop meta-table, it will be recreated
@@ -1732,13 +1758,60 @@ int cloudsync_finalize_alter (sqlite3_context *context, cloudsync_context *data,
17321758 // update key to be later used in cloudsync_dbversion_rebuild
17331759 char buf [256 ];
17341760 snprintf (buf , sizeof (buf ), "%lld" , data -> db_version );
1735- dbutils_settings_set_key_value (db , context , "pre_alter_dbversion" , buf );
1761+ dbutils_settings_set_key_value (db , NULL , "pre_alter_dbversion" , buf );
17361762
17371763finalize :
1738- // free result
1739- for (int i = 0 ; i < nrows ; ++ i ) {dbmem_free (result [i ]);}
1740- dbmem_free (result );
1764+ table_pknames_free (result , nrows );
1765+ return rc ;
1766+ }
1767+
1768+ int cloudsync_commit_alter (cloudsync_context * data , const char * table_name ) {
1769+ db_t * db = data -> db ;
1770+ int rc = DBRES_MISUSE ;
1771+ cloudsync_table_context * table = NULL ;
1772+
1773+ // init cloudsync_settings
1774+ if (cloudsync_context_init (data , db , NULL ) == NULL ) {
1775+ cloudsync_set_error (data , "Unable to initialize cloudsync context" , DBRES_MISUSE );
1776+ goto rollback_finalize_alter ;
1777+ }
1778+
1779+ // lookup table
1780+ table = table_lookup (data , table_name );
1781+ if (!table ) {
1782+ char buffer [1024 ];
1783+ snprintf (buffer , sizeof (buffer ), "Unable to find table %s" , table_name );
1784+ cloudsync_set_error (data , buffer , DBRES_MISUSE );
1785+ goto rollback_finalize_alter ;
1786+ }
1787+
1788+ rc = cloudsync_finalize_alter (data , table );
1789+ if (rc != SQLITE_OK ) goto rollback_finalize_alter ;
1790+
1791+ // the table is outdated, delete it and it will be reloaded in the cloudsync_init_internal
1792+ table_remove (data , table );
1793+ table_free (table );
1794+ table = NULL ;
1795+
1796+ // init again cloudsync for the table
1797+ table_algo algo_current = dbutils_table_settings_get_algo (db , table_name );
1798+ if (algo_current == table_algo_none ) algo_current = dbutils_table_settings_get_algo (db , "*" );
1799+ rc = cloudsync_init_table (data , table_name , crdt_algo_name (algo_current ), true);
1800+ if (rc != SQLITE_OK ) goto rollback_finalize_alter ;
1801+
1802+ // release savepoint
1803+ rc = database_exec (db , "RELEASE cloudsync_alter;" );
1804+ if (rc != SQLITE_OK ) {
1805+ cloudsync_set_dberror (data );
1806+ goto rollback_finalize_alter ;
1807+ }
1808+
1809+ cloudsync_update_schema_hash (data );
1810+ return DBRES_OK ;
17411811
1812+ rollback_finalize_alter :
1813+ database_exec (db , "ROLLBACK TO cloudsync_alter; RELEASE cloudsync_alter;" );
1814+ if (table ) table_set_pknames (table , NULL );
17421815 return rc ;
17431816}
17441817
0 commit comments