# SM006: rename_column

| Property       | Value         |
| -------------- | ------------- |
| **Rule ID**    | SM006         |
| **Severity**   | INFO          |
| **Name**       | rename_column |
| **Applies to** | All databases |

## What Triggers This Rule

This rule triggers when a migration contains `RenameField`:

```python
# Triggers SM006
migrations.RenameField(
    model_name='user',
    old_name='name',
    new_name='full_name',
)
```

## Why It's Dangerous

Renaming a column is an instant operation, but it breaks code that references the old name:

1. **Old code fails** — Queries using the old column name crash
2. **ORM breaks** — Django model expects the old name
3. **Raw SQL breaks** — Any hardcoded column references fail
4. **External systems break** — APIs, reports, integrations using the column

### Real-World Failure Scenario

```
Timeline (rolling deployment):
├─ 0:00  Migration runs → column renamed
├─ 0:01  Server 1 (old code): SELECT name FROM users
├─ 0:01  Database: ERROR - column "name" does not exist
├─ 0:01  User sees 500 error
├─ ...
├─ 0:05  Server 1 gets new code
└─ 0:05  All servers using "full_name"
```

## When It's Safe to Ignore

This warning can be safely ignored when:

1. **Using blue-green deployment** — Complete cutover, no rolling update
2. **Maintenance mode enabled** — No traffic during deployment
3. **The column is unused** — No code references the old name
4. **Coordinated release** — All code deployed atomically

## How to Fix It

### Recommended: Add-Copy-Remove Pattern

Instead of renaming, create a new column and migrate data:

**Step 1: Add new column**

```python
migrations.AddField(
    model_name='user',
    name='full_name',
    field=models.CharField(max_length=255, null=True),
)
```

**Step 2: Copy data**

```python
def copy_name_to_full_name(apps, schema_editor):
    User = apps.get_model('myapp', 'User')
    User.objects.all().update(full_name=models.F('name'))

migrations.RunPython(copy_name_to_full_name, migrations.RunPython.noop)
```

**Step 3: Update application code**

Update all code to use `full_name` instead of `name`. Deploy this change.

**Step 4: Remove old column**

After all servers have the new code:

```python
migrations.RemoveField(
    model_name='user',
    name='name',
)
```

### Using Database Trigger (Advanced)

For zero-downtime, keep both columns in sync with a trigger:

```python
migrations.RunSQL(
    sql='''
        CREATE OR REPLACE FUNCTION sync_name_columns()
        RETURNS TRIGGER AS $$
        BEGIN
            IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
                NEW.full_name := COALESCE(NEW.full_name, NEW.name);
                NEW.name := COALESCE(NEW.name, NEW.full_name);
            END IF;
            RETURN NEW;
        END;
        $$ LANGUAGE plpgsql;

        CREATE TRIGGER sync_user_names
        BEFORE INSERT OR UPDATE ON myapp_user
        FOR EACH ROW EXECUTE FUNCTION sync_name_columns();
    ''',
    reverse_sql='''
        DROP TRIGGER IF EXISTS sync_user_names ON myapp_user;
        DROP FUNCTION IF EXISTS sync_name_columns();
    ''',
)
```

## How to Suppress

### In Django Settings

```python
SAFE_MIGRATIONS = {
    "DISABLED_RULES": ["SM006"],
}
```

### Change Severity to WARNING

If you want to be alerted but not at INFO level:

```python
SAFE_MIGRATIONS = {
    "RULE_SEVERITY": {
        "SM006": "WARNING",
    },
}
```

## See Also

- [SM002: drop_column_unsafe](SM002.md) — Related column modification rule
- [SM014: rename_model](SM014.md) — Similar rule for renaming models
- [Safe Patterns: Renaming Columns](../patterns.md#renaming-columns)
