@@ -103,6 +103,7 @@ SQL command timeout constants (in seconds)
103103 private const int ShortTimeoutSeconds = 60 ; // Quick operations (cleanup, queries)
104104 private const int MediumTimeoutSeconds = 120 ; // Dependency installation
105105 private const int LongTimeoutSeconds = 300 ; // SQL file execution (5 minutes)
106+ private const int UpgradeTimeoutSeconds = 3600 ; // Upgrade data migrations (1 hour, large tables)
106107
107108 /*
108109 Exit codes for granular error reporting
@@ -117,6 +118,7 @@ private static class ExitCodes
117118 public const int VersionCheckFailed = 5 ;
118119 public const int SqlFilesNotFound = 6 ;
119120 public const int UninstallFailed = 7 ;
121+ public const int UpgradesFailed = 8 ;
120122 }
121123
122124 static async Task < int > Main ( string [ ] args )
@@ -523,8 +525,9 @@ Search current directory and up to 5 parent directories
523525 string fileName = Path . GetFileName ( f ) ;
524526 if ( ! SqlFileNamePattern . IsMatch ( fileName ) )
525527 return false ;
526- /*Exclude test and troubleshooting scripts from main install*/
527- if ( fileName . StartsWith ( "97_" , StringComparison . Ordinal ) ||
528+ /*Exclude uninstall, test, and troubleshooting scripts from main install*/
529+ if ( fileName . StartsWith ( "00_" , StringComparison . Ordinal ) ||
530+ fileName . StartsWith ( "97_" , StringComparison . Ordinal ) ||
528531 fileName . StartsWith ( "99_" , StringComparison . Ordinal ) )
529532 return false ;
530533 return true ;
@@ -699,6 +702,21 @@ Traces are server-level and persist after database drops
699702
700703 Console . WriteLine ( ) ;
701704 Console . WriteLine ( $ "Upgrades complete: { upgradeSuccessCount } succeeded, { upgradeFailureCount } failed") ;
705+
706+ /*Abort if any upgrade scripts failed — proceeding would reinstall over a partially-upgraded database*/
707+ if ( upgradeFailureCount > 0 )
708+ {
709+ Console . WriteLine ( ) ;
710+ Console . WriteLine ( "================================================================================" ) ;
711+ Console . WriteLine ( "Installation aborted: upgrade scripts must succeed before installation can proceed." ) ;
712+ Console . WriteLine ( "Fix the errors above and re-run the installer." ) ;
713+ Console . WriteLine ( "================================================================================" ) ;
714+ if ( ! automatedMode )
715+ {
716+ WaitForExit ( ) ;
717+ }
718+ return ExitCodes . UpgradesFailed ;
719+ }
702720 }
703721 else
704722 {
@@ -1332,7 +1350,15 @@ FROM PerformanceMonitor.config.installation_history
13321350 return version . ToString ( ) ;
13331351 }
13341352
1335- return null ;
1353+ /*
1354+ Fallback: database and history table exist but no SUCCESS rows.
1355+ This can happen if a prior GUI install didn't write history (#538/#539).
1356+ Return "1.0.0" so all idempotent upgrade scripts are attempted
1357+ rather than treating this as a fresh install (which would drop the database).
1358+ */
1359+ Console . WriteLine ( "Warning: PerformanceMonitor database exists but installation_history has no records." ) ;
1360+ Console . WriteLine ( "Treating as v1.0.0 to apply all available upgrades." ) ;
1361+ return "1.0.0" ;
13361362 }
13371363 }
13381364 catch ( SqlException ex )
@@ -1480,7 +1506,7 @@ Execute an upgrade folder
14801506
14811507 using ( var cmd = new SqlCommand ( trimmedBatch , connection ) )
14821508 {
1483- cmd . CommandTimeout = LongTimeoutSeconds ;
1509+ cmd . CommandTimeout = UpgradeTimeoutSeconds ;
14841510 try
14851511 {
14861512 await cmd . ExecuteNonQueryAsync ( ) . ConfigureAwait ( false ) ;
0 commit comments