# 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)

