Skip to content

Commit ec12913

Browse files
committed
Fix MUC room created_at timestamp and add updated_at field
- Add updated_at column to muc_room table schema - Use UPSERT special syntax (-created_at) to preserve created_at on updates - Set created_at to current time for new rooms (not 1970-01-02) - Add hibernation_time support in format_room_option - Update SQL files: mysql.new.sql, pg.new.sql, lite.new.sql, mssql.new.sql - Include migration guide and SQL scripts This fixes the issue where newly created MUC rooms have created_at = 1970-01-02 00:00:00 instead of actual creation time. The solution: - Uses ejabberd's UPSERT special syntax where '-field' means 'only set on INSERT, not on UPDATE' - Adds updated_at column to properly track room modifications - Separates concerns: created_at vs updated_at vs hibernation_time
1 parent 0ca877f commit ec12913

13 files changed

Lines changed: 484 additions & 15 deletions

MIGRATION_GUIDE.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
# Migration Guide: Add `updated_at` to MUC Rooms
2+
3+
## Overview
4+
5+
This migration adds an `updated_at` column to the `muc_room` table to properly track when rooms are modified, separate from when they were created.
6+
7+
## Why This Change?
8+
9+
Previously, the `created_at` field was incorrectly:
10+
1. Set to `1970-01-02 00:00:00` for new rooms
11+
2. Updated every time the room was modified
12+
3. Confused with `hibernation_time` (when room goes to sleep)
13+
14+
This migration fixes these issues by:
15+
- Ensuring `created_at` is set correctly on room creation and never changes
16+
- Adding `updated_at` to track when room configuration is modified
17+
- Separating concerns between creation time, update time, and hibernation time
18+
19+
## Prerequisites
20+
21+
1. Backup your database before running migration
22+
2. Stop ejabberd or ensure no rooms are being created/modified during migration
23+
3. Compile the new ejabberd code
24+
25+
## Migration Steps
26+
27+
### Step 1: Backup Database
28+
29+
```bash
30+
# MySQL
31+
mysqldump -u root -p ejabberd > ejabberd_backup_$(date +%Y%m%d).sql
32+
33+
# PostgreSQL
34+
pg_dump ejabberd > ejabberd_backup_$(date +%Y%m%d).sql
35+
36+
# SQLite
37+
cp /path/to/ejabberd.db /path/to/ejabberd_backup_$(date +%Y%m%d).db
38+
```
39+
40+
### Step 2: Run Migration SQL
41+
42+
#### For MySQL/MariaDB:
43+
44+
```sql
45+
USE ejabberd;
46+
47+
-- Add updated_at column
48+
ALTER TABLE muc_room ADD COLUMN updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
49+
50+
-- Initialize updated_at with created_at value
51+
UPDATE muc_room SET updated_at = created_at;
52+
53+
-- Verify
54+
SELECT name, host, created_at, updated_at FROM muc_room LIMIT 10;
55+
```
56+
57+
#### For PostgreSQL:
58+
59+
```sql
60+
\c ejabberd;
61+
62+
-- Add updated_at column
63+
ALTER TABLE muc_room ADD COLUMN updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
64+
65+
-- Initialize updated_at with created_at value
66+
UPDATE muc_room SET updated_at = created_at;
67+
68+
-- Verify
69+
SELECT name, host, created_at, updated_at FROM muc_room LIMIT 10;
70+
```
71+
72+
#### For SQLite:
73+
74+
```sql
75+
-- Add updated_at column
76+
ALTER TABLE muc_room ADD COLUMN updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
77+
78+
-- Initialize updated_at with created_at value
79+
UPDATE muc_room SET updated_at = created_at;
80+
81+
-- Verify
82+
SELECT name, host, created_at, updated_at FROM muc_room LIMIT 10;
83+
```
84+
85+
#### For MSSQL:
86+
87+
```sql
88+
USE ejabberd;
89+
90+
-- Add updated_at column
91+
ALTER TABLE muc_room ADD updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP;
92+
93+
-- Initialize updated_at with created_at value
94+
UPDATE muc_room SET updated_at = created_at;
95+
96+
-- Verify
97+
SELECT TOP 10 name, host, created_at, updated_at FROM muc_room;
98+
```
99+
100+
### Step 3: Compile and Restart ejabberd
101+
102+
```bash
103+
cd /path/to/ejabberd
104+
./rebar3 compile
105+
ejabberdctl restart
106+
```
107+
108+
### Step 4: Verify
109+
110+
```bash
111+
# Create a test room
112+
ejabberdctl create_room testroom conference.localhost localhost
113+
114+
# Check database
115+
# MySQL/PostgreSQL/SQLite:
116+
SELECT name, created_at, updated_at FROM muc_room WHERE name='testroom';
117+
118+
# Both timestamps should be current time and equal
119+
120+
# Update room option
121+
ejabberdctl change_room_option testroom conference.localhost title "Test Room"
122+
123+
# Check database again
124+
SELECT name, created_at, updated_at FROM muc_room WHERE name='testroom';
125+
126+
# created_at should be unchanged, updated_at should be newer
127+
```
128+
129+
## Rollback
130+
131+
If you need to rollback:
132+
133+
```sql
134+
-- MySQL/PostgreSQL/SQLite
135+
ALTER TABLE muc_room DROP COLUMN updated_at;
136+
137+
-- MSSQL
138+
ALTER TABLE muc_room DROP COLUMN updated_at;
139+
```
140+
141+
Then restore your backup and use the old ejabberd code.
142+
143+
## Troubleshooting
144+
145+
### Issue: Migration fails with "column already exists"
146+
147+
**Solution:** The column may have been added in a previous attempt. Check if it exists:
148+
149+
```sql
150+
-- MySQL
151+
SHOW COLUMNS FROM muc_room LIKE 'updated_at';
152+
153+
-- PostgreSQL
154+
SELECT column_name FROM information_schema.columns
155+
WHERE table_name='muc_room' AND column_name='updated_at';
156+
157+
-- SQLite
158+
PRAGMA table_info(muc_room);
159+
```
160+
161+
If it exists, skip to Step 3.
162+
163+
### Issue: Old rooms still have `1970-01-02` in `created_at`
164+
165+
**Solution:** This is expected for rooms created before the migration. You can optionally update them:
166+
167+
```sql
168+
-- Set created_at to updated_at for old rooms
169+
UPDATE muc_room
170+
SET created_at = updated_at
171+
WHERE created_at < '1971-01-01 00:00:00';
172+
```
173+
174+
### Issue: Performance concerns on large databases
175+
176+
**Solution:** For very large `muc_room` tables (>1M rows), consider:
177+
178+
1. Add the column without default first:
179+
```sql
180+
ALTER TABLE muc_room ADD COLUMN updated_at timestamp NULL;
181+
```
182+
183+
2. Update in batches:
184+
```sql
185+
-- MySQL
186+
UPDATE muc_room SET updated_at = created_at WHERE updated_at IS NULL LIMIT 10000;
187+
-- Repeat until all rows updated
188+
189+
-- PostgreSQL
190+
UPDATE muc_room SET updated_at = created_at WHERE updated_at IS NULL;
191+
```
192+
193+
3. Make it NOT NULL after all rows are updated:
194+
```sql
195+
ALTER TABLE muc_room MODIFY updated_at timestamp NOT NULL;
196+
```
197+
198+
## Benefits After Migration
199+
200+
1. ✅ Accurate room creation timestamps
201+
2. ✅ Track when room configuration changes
202+
3. ✅ Better analytics and reporting
203+
4. ✅ Clearer separation of concerns
204+
5. ✅ No more `1970-01-02 00:00:00` timestamps!
205+
206+
## Support
207+
208+
If you encounter issues, please report them on the ejabberd GitHub repository with:
209+
- Database type and version
210+
- ejabberd version
211+
- Error messages
212+
- Output of `SELECT * FROM muc_room LIMIT 1;`

0 commit comments

Comments
 (0)