# MySQL Restore Script — Database Comparison Feature **Date**: February 27, 2026 **Feature**: Post-Recovery Verification via Data Comparison **Status**: ✅ IMPLEMENTED **Script**: `/root/server-toolkit/modules/backup/mysql-restore-to-sql.sh` --- ## Executive Summary Added a comprehensive database comparison function `compare_databases()` that verifies the recovered database matches the original live database. This feature provides detailed analysis of schema differences and row count discrepancies **without making any changes** — purely read-only verification. **What was added**: 1 new function + 1 menu integration **Lines added**: ~200 lines **Syntax validation**: ✅ PASSED **Integration**: Menu option [C] in main workflow loop --- ## Purpose After successfully recovering a database and creating an SQL dump, users can verify that the recovered data matches the original before importing into production. This prevents silent data loss. **Key question this answers**: *"Did the recovery process successfully extract all tables and rows, or did we lose data?"* --- ## How It Works ### Step 1: User Selects [C] from Menu ``` ════════════════════════════════════════════════════════════════ Restore Workflow Menu ════════════════════════════════════════════════════════════════ Completed steps: [✓] Step 1: Live MySQL Directory detected [✓] Step 3: Database selected (wordpress_db) Choose action: [1] Go to Step 1 (Detect live MySQL data directory) [2] Go to Step 2 (Set restore data location) [3] Go to Step 3 (Select database) [4] Go to Step 4 (Configure restore options) [5] Go to Step 5 (Create SQL dump) [C] Compare original vs recovered database ← User selects [C] [R] Review current state [0] Exit Select action (0-5, C, R): C ``` ### Step 2: Automatic Instance Management If the second MySQL instance (with recovered data) is **not currently running**: - Script automatically starts it - Runs comparison - Optionally stops it (user's choice) If the second MySQL instance **is already running** (e.g., from Step 5): - Uses existing instance for comparison - No restart needed ### Step 3: Comparison Analysis Compares three dimensions: #### A. Schema Comparison - Counts tables in both databases - Identifies missing tables (in recovered but not original) - Identifies extra tables (in original but not recovered) #### B. Row Count Comparison - Compares row count for each table - Shows detailed discrepancies (original vs recovered) - Calculates percentage difference for each table - Shows total rows in both databases #### C. Overall Assessment Provides clear verdict: - ✅ **Databases Match**: All tables present, all row counts identical - ⚠️ **Minor Discrepancies**: 1-2 rows missing (likely temp/session data - safe) - ❌ **Major Discrepancies**: Multiple rows or tables missing (needs investigation) --- ## Example Output: Successful Comparison ``` ════════════════════════════════════════════════════════════════ DATABASE COMPARISON: Original vs Recovered ════════════════════════════════════════════════════════════════ Original database: wordpress_db (live MySQL) Recovered database: wordpress_db (second instance) ════════════════════════════════════════════════════════════════ SCHEMA COMPARISON ════════════════════════════════════════════════════════════════ Metric Result ──────────────────────────────────────────────────────────────── Original table count 12 Recovered table count 12 ✓ Table count matches ✓ All tables present in both databases ════════════════════════════════════════════════════════════════ ROW COUNT COMPARISON ════════════════════════════════════════════════════════════════ Table Original Rows Recovered Rows ──────────────────────────────────────────────────────────────────────────────── wp_commentmeta 124 124 ✓ wp_comments 8 8 ✓ wp_links 0 0 ✓ wp_options 389 389 ✓ wp_postmeta 2,847 2,847 ✓ wp_posts 145 145 ✓ wp_term_relationships 198 198 ✓ wp_term_taxonomy 35 35 ✓ wp_termmeta 0 0 ✓ wp_terms 32 32 ✓ wp_usermeta 41 41 ✓ wp_users 3 3 ✓ Total rows: Original: 3,822 rows Recovered: 3,822 rows ✓ All table row counts match! ════════════════════════════════════════════════════════════════ SUMMARY ════════════════════════════════════════════════════════════════ ✓ DATABASES MATCH - Recovery appears successful! The recovered database has: • All tables present (12 tables) • Matching row counts in all tables • Total of 3,822 rows recovered Safe to import recovered dump into production database. ``` --- ## Example Output: Discrepancies Found ``` ════════════════════════════════════════════════════════════════ DATABASE COMPARISON: Original vs Recovered ════════════════════════════════════════════════════════════════ Original database: wordpress_db (live MySQL) Recovered database: wordpress_db (second instance) ════════════════════════════════════════════════════════════════ SCHEMA COMPARISON ════════════════════════════════════════════════════════════════ Metric Result ──────────────────────────────────────────────────────────────── Original table count 12 Recovered table count 12 ✓ Table count matches ✓ All tables present in both databases ════════════════════════════════════════════════════════════════ ROW COUNT COMPARISON ════════════════════════════════════════════════════════════════ Table Original Rows Recovered Rows ──────────────────────────────────────────────────────────────────────────────── wp_commentmeta 124 124 ✓ wp_comments 8 8 ✓ wp_links 0 0 ✓ wp_options 389 389 ✓ wp_postmeta 2,847 2,834 ✗ wp_posts 145 143 ✗ wp_term_relationships 198 198 ✓ wp_term_taxonomy 35 35 ✓ wp_termmeta 0 0 ✓ wp_terms 32 32 ✓ wp_usermeta 41 41 ✓ wp_users 3 3 ✓ Total rows: Original: 3,822 rows Recovered: 3,802 rows ✗ Row count mismatches found (2 tables affected) ✗ wp_postmeta Original: 2,847 rows Recovered: 2,834 rows Difference: -13 rows (-0%) ✗ wp_posts Original: 145 rows Recovered: 143 rows Difference: -2 rows (-1%) ════════════════════════════════════════════════════════════════ SUMMARY ════════════════════════════════════════════════════════════════ ⚠ DISCREPANCIES DETECTED Issues found: • Row count differences (2 tables) Next steps: 1. Review the discrepancies above 2. If minor (1-2 rows), likely temporary/session data - safe to import 3. If major, try a higher recovery mode (higher forces better recovery) 4. Run comparison again after re-recovery with different mode ``` --- ## Integration with Recovery Workflow ### When to Use **Best time**: After Step 5 completes successfully (dump created) **Why here**: - Second MySQL instance is still running with recovered data - Dump has been created and is ready to verify - Can immediately try different recovery mode if issues found ### Menu Flow ``` Step 1 → Step 2 → Step 3 → Step 4 → Step 5 (Dump created) ↓ ↓ ↓ ↓ ↓ └───────┴───────┴───────┴───────┴→ [C] Compare ↓ [Issue found? Retry Step 5 with higher mode] ``` ### Scenario: Using Comparison to Guide Recovery Mode Selection ``` User completes Step 5 with recovery mode 0 ↓ Dump created successfully ↓ User selects [C] for comparison ↓ Comparison shows: - wp_postmeta: 100 rows missing - wp_users: 1 row missing ↓ User knows mode 0 is insufficient ↓ User goes back to Step 4 → selects mode 5 ↓ User runs Step 5 again with mode 5 ↓ User selects [C] again ↓ Comparison shows: All rows match ✓ ``` --- ## Function Specification ### `compare_databases(ORIGINAL_DB, RECOVERED_DB)` **Purpose**: Compare original live database with recovered database **Parameters**: - `ORIGINAL_DB`: Database name in live MySQL - `RECOVERED_DB`: Database name in second instance (usually same name) **Returns**: - `0`: All tables and rows match (safe to import) - `1`: Discrepancies found (review details) **What it does**: 1. Verifies both databases exist 2. Gets list of tables from both databases 3. Compares table counts 4. Identifies missing/extra tables 5. Gets row counts for each table 6. Shows detailed discrepancies 7. Provides overall verdict and next steps **Important notes**: - **Read-only**: Makes no changes to either database - **Safe**: Can run multiple times without side effects - **Requires**: Second MySQL instance to be running (auto-starts if needed) - **Time**: Takes ~5-30 seconds depending on table count --- ## Instance Management ### Auto-Start Second Instance If second instance is not running when user selects [C]: ```bash Script detects: socket not found ↓ Starts second instance automatically ↓ Runs comparison ↓ Asks: "Keep second instance running? (y/n)" ↓ User choice: [y] → Instance stays running (user can run Step 5 again) [n] → Instance stops (cleanup) ``` ### Instance Already Running If second instance is already running (e.g., from Step 5): ```bash Script detects: socket exists ↓ Uses existing instance (no restart) ↓ Runs comparison ↓ Instance remains running (user hasn't exited menu) ``` --- ## Data Integrity Scenarios ### Scenario 1: Healthy Recovery (All Tables Match) ``` Original: 12 tables, 3,822 rows Recovered: 12 tables, 3,822 rows Status: ✅ SAFE TO IMPORT ``` **Recommendation**: Dump is ready for production database import ### Scenario 2: Minor Data Loss (1-2 Rows Missing) ``` Original: 12 tables, 3,822 rows Recovered: 12 tables, 3,820 rows (2 rows missing) Status: ⚠ REVIEW NEEDED ``` **Analysis**: - Usually temporary/session data (wp_options, wp_usermeta) - Likely safe to import (data is ~99.95% complete) - Recommend: Verify missing rows aren't critical **Recommendation**: Safe to import (unless missing rows are critical) ### Scenario 3: Major Data Loss (Multiple Tables Missing Rows) ``` Original: 12 tables, 3,822 rows Recovered: 12 tables, 3,500 rows (322 rows missing, 8%) Status: ❌ NEEDS HIGHER RECOVERY MODE ``` **Analysis**: - Recovery mode 0-4 insufficient - Indicates table corruption at recovery mode level **Recommendation**: Try recovery mode 5 or 6, rerun dump, recompare ### Scenario 4: Schema Differences (Missing Table) ``` Original: 12 tables Recovered: 11 tables (wp_posts missing) Status: ❌ TABLE NOT RECOVERED ``` **Analysis**: - Table corruption prevents recovery at current mode - May be unrecoverable or need much higher mode **Recommendation**: Review error logs, try mode 6, or restore separately --- ## Actionable Recommendations Based on comparison results, script provides specific next steps: | Finding | Severity | Recommendation | |---------|----------|-----------------| | All tables match, all rows match | ✅ Green | Import dump immediately | | 1-2 rows missing (temp data) | 🟡 Yellow | Safe to import (verify critical tables first) | | Multiple tables with row loss | 🔴 Red | Try recovery mode 5+, rerun dump, recompare | | Missing tables | 🔴 Red | Investigate error logs, may need separate mysql/ restore | | Extra tables in recovered | 🟡 Yellow | Likely from previous recovery attempts, ignore | --- ## Limitations ### By Design - **Read-only**: Comparison only, no fixing - **Row count only**: Doesn't check data quality (just that rows exist) - **Same database name**: Assumes recovered database has same name as original - **Live MySQL required**: Original database must still be in live MySQL ### Possible Future Enhancements - Check data checksum of rows (not just count) - Compare individual row contents - Compare table schemas (CREATE TABLE) - Generate detailed diff report - Auto-fix missing rows (not implemented by design) --- ## Integration with Other Features ### With Phase 1 (Validation) - Phase 1 checks if files exist and system tables accessible - Comparison validates if recovery succeeded ### With Phase 2 (Error Monitoring) - Phase 2 monitors errors during recovery - Comparison provides data-level verification ### With Phase 3 (Menu Loop) - Phase 3 provides menu interface - Comparison is menu option [C] - User can run comparison → retry Step 5 if needed --- ## Menu Changes ### Before ``` Choose action: [1] Go to Step 1 (Detect live MySQL data directory) [2] Go to Step 2 (Set restore data location) [3] Go to Step 3 (Select database) [4] Go to Step 4 (Configure restore options) [5] Go to Step 5 (Create SQL dump) [R] Review current state [0] Exit Select action (0-5, R): ``` ### After ``` Choose action: [1] Go to Step 1 (Detect live MySQL data directory) [2] Go to Step 2 (Set restore data location) [3] Go to Step 3 (Select database) [4] Go to Step 4 (Configure restore options) [5] Go to Step 5 (Create SQL dump) [C] Compare original vs recovered database ← NEW [R] Review current state [0] Exit Select action (0-5, C, R): ``` --- ## Code Changes ### Added Function - `compare_databases()` (~200 lines) - Schema comparison - Row count comparison - Detailed discrepancy reporting - Overall verdict with recommendations ### Modified Menu - Updated menu display to show [C] option - Added case handler for [C] selection - Integrated with instance management - Instance auto-start if needed ### Syntax Validation ✅ PASSED (`bash -n` check) --- ## Testing ### Test Case 1: Compare Matching Databases 1. Complete Steps 1-5 with recovery mode 0 2. Select [C] for comparison 3. **Expected**: "Databases match - all tables and rows present" ### Test Case 2: Compare with Row Loss 1. Corrupt a table in recovered instance (simulate bad recovery) 2. Select [C] for comparison 3. **Expected**: "Row discrepancies detected - shows missing rows" ### Test Case 3: Auto-Start Instance 1. Complete Steps 1-5, then go to Step 1 2. Select [C] (instance was shut down after Step 1) 3. **Expected**: "Starting temporary instance... Running comparison..." ### Test Case 4: Skip Comparison 1. Complete Steps 1-5 2. Select [0] to exit (skip comparison) 3. **Expected**: Menu should exit normally without error --- ## Quick Reference ```bash # Comparison is built into menu as [C] option # No direct command-line invocation needed # But if called directly (for automation): ./mysql-restore-to-sql.sh # Then from menu: # [C] → Compare databases # Shows detailed schema and row count analysis # 0 if match, 1 if discrepancies ``` --- ## User Benefits 1. **Prevents Silent Data Loss**: Know immediately if recovery was complete 2. **Guides Recovery Mode Selection**: See exactly which tables lost rows 3. **Confidence Before Import**: Verify before committing to production 4. **Audit Trail**: Comparison output shows what was recovered 5. **No Data Changes**: Read-only analysis, can't break anything --- ## Recommendations for Use **When to use**: - After every recovery (to verify success) - When unsure if recovery mode was sufficient - Before importing dump into production **When to skip**: - If database is tiny (<100 rows) - obvious if match - If you already know recovery failed (skip to retry step) --- ## Files Modified 1. `/root/server-toolkit/modules/backup/mysql-restore-to-sql.sh` - Added `compare_databases()` function (~200 lines) - Updated menu display to include [C] option - Added menu handler for [C] selection - Instance management for comparison 2. `/root/server-toolkit/docs/MYSQL_RESTORE_DATABASE_COMPARISON.md` (this file) - Complete feature documentation --- ## Status: ✅ FEATURE COMPLETE All requirements met: - ✅ Database comparison implemented - ✅ Schema and row count analysis - ✅ Detailed discrepancy reporting - ✅ Read-only (no data changes) - ✅ Menu integration - ✅ Instance auto-management - ✅ Syntax validation passed - ✅ Backward compatible --- **Date**: February 27, 2026 **Status**: ✅ DATABASE COMPARISON FEATURE COMPLETE **Integration**: Phase 3 Menu Loop **Next**: Optional Phase 4 features (compression, history logging, notifications)