Skip to main content

Recover dropped objects

Running DROP TABLE against the wrong database is an easy mistake to make. In PostgreSQL or MySQL, the data is gone and you restore a backup. CamusDB lets you undo an accidental DROP: it keeps a dropped root database or table recoverable during a configurable retention window, and a RELINK statement brings it back. The same applies to a wrong cleanup script or a destructive migration. As long as CamusDB still keeps the orphan, you recover without restoring a full backup.

An ordinary DROP DATABASE or DROP TABLE removes the object from the catalog and frees its name immediately. CamusDB still keeps the object's data as a recoverable orphan until it reclaims that orphan.

Quick workflow​

This real camus-cli session recovers a dropped database. Drop the database, then list the recoverable orphans:

DROP DATABASE test;
SHOW ORPHAN DATABASES;
┌────┬─────────────┬────────────────────────┬────────────────────────┐
│ id │ former_name │ dropped_at │ expires_at │
├────┼─────────────┼────────────────────────┼────────────────────────┤
│ I │ test │ HLC(1:1784427365296:2) │ HLC(1:1785032165296:2) │
└────┴─────────────┴────────────────────────┴────────────────────────┘
1 rows in set (00:00:00.0135411)

The dropped_at and expires_at values are cluster timestamps (HLC). The orphan stays recoverable until expires_at. Recover it under a name, then check its tables:

CREATE DATABASE test RELINK TO 'I';
USE test;
SHOW TABLES;
┌─────────────────┐
│ tables │
├─────────────────┤
│ orders_restored │
│ orders │
└─────────────────┘
2 rows in set (00:00:00.0036480)

The same pattern works for a table in the current database:

DROP TABLE orders;
SHOW ORPHAN TABLES;
┌────┬─────────────┬────────────────────────┬────────────────────────┐
│ id │ former_name │ dropped_at │ expires_at │
├────┼─────────────┼────────────────────────┼────────────────────────┤
│ s6 │ orders │ HLC(1:1784427567387:0) │ HLC(1:1785032367387:0) │
└────┴─────────────┴────────────────────────┴────────────────────────┘
1 rows in set (00:00:00.0068052)
CREATE TABLE orders RELINK TO 's6';
DESC orders;
┌───────┬────────────┬──────┬─────┬──────────┬───────┐
│ Field │ Type │ Null │ Key │ Default │ Extra │
├───────┼────────────┼──────┼─────┼──────────┼───────┤
│ id │ OID │ NO │ PRI │ gen_id() │ │
│ name │ STRING(20) │ YES │ │ NULL │ │
└───────┴────────────┴──────┴─────┴──────────┴───────┘
2 rows in set (00:00:00.0073021)

RELINK TO takes the orphan id that SHOW ORPHAN TABLES and SHOW ORPHAN DATABASES show. Treat the id as an opaque string.

Orphan table kinds​

SHOW ORPHAN TABLES has one more column, kind. CamusDB retains two different things that would look the same without it:

kindWhat it isIs former_name a live table?
dropped tableA table that somebody dropped.No. CamusDB freed the name.
retired contentsContents that a still-live table stopped reading after a TRUNCATE.Yes. That table still exists, and it is empty.

Recovering retired contents publishes the retained rows as a separate new table with a fresh relation id. It does not affect the table named in former_name. See TRUNCATE TABLE.

SHOW ORPHAN DATABASES has no kind column. A dropped database is always a dropped database.

What a plain DROP does​

A plain drop is deferred, and it is recoverable:

DROP DATABASE sales;
DROP TABLE orders;

After the statement succeeds:

  • You can reuse the database or table name immediately.
  • SHOW DATABASES and SHOW TABLES no longer list the object.
  • Queries against the dropped object fail, because the object is absent.
  • CamusDB keeps the rows, indexes, constraints, and schema metadata as an orphan.
  • You can recover the orphan under a new name with RELINK TO.

CamusDB never reuses object ids. If you drop sales and then create a new database named sales, the new database gets a new id, and the old data stays recoverable under its orphan id.

DROP DATABASE sales;
CREATE DATABASE sales;

SHOW ORPHAN DATABASES;
CREATE DATABASE sales_before_migration RELINK TO '7';

The new database stays online while you recover the previous data under a safe name for inspection.

Recover a database​

Run SHOW ORPHAN DATABASES from any connection. It needs no current database.

SHOW ORPHAN DATABASES;

The result shows each orphan's id, former name, drop timestamp, and expiry timestamp.

To recover the database, create a new name and link it to that id:

CREATE DATABASE sales_recovered RELINK TO '7';
USE sales_recovered;
SHOW TABLES;

The recovered database holds the retained tables and data as they were at the moment of the drop.

Recover a table​

Table recovery runs inside the current database. Select the database that owned the table first, then inspect the orphan tables:

USE sales;
SHOW ORPHAN TABLES;

Recover the table under a new table name:

CREATE TABLE orders_recovered RELINK TO 'A0';
SELECT * FROM orders_recovered LIMIT 10;

The recovered table keeps its rows, indexes, primary key, unique constraints, check constraints, and column definitions from the time of the drop.

Foreign keys are not restored with a recovered table. A parent table may have been dropped, changed, or recovered under another name while the child was absent. Add the foreign keys again with ALTER TABLE ... ADD CONSTRAINT; that statement validates the recovered rows before the constraint becomes public.

Permanent drop with FORCE​

Use FORCE only when CamusDB must delete the object immediately and permanently:

DROP DATABASE staging FORCE;
DROP TABLE scratch FORCE;
DROP DATABASE IF EXISTS old_test FORCE;
DROP TABLE IF EXISTS temp_rows FORCE;

A forced drop creates no orphan record. The object appears in neither SHOW ORPHAN DATABASES nor SHOW ORPHAN TABLES, and RELINK TO cannot recover it.

Retention settings​

Two configuration values control how long recovery is possible:

SettingDefaultMeaning
orphan_retention_ms604800000How long an orphan stays eligible for recovery before CamusDB may reclaim it. The default is seven days. A value of 0 or below keeps orphans indefinitely.
orphan_reclaim_interval_ms300000How often the background reclaimer checks for expired orphans. The default is five minutes. A value of 0 or below disables the automatic sweep.

For example:

# Keep dropped databases and tables recoverable for 30 days.
orphan_retention_ms: 2592000000
orphan_reclaim_interval_ms: 300000

The expiry time that SHOW ORPHAN DATABASES and SHOW ORPHAN TABLES show is when the object becomes eligible for reclamation. Recovery can still succeed until CamusDB actually reclaims the object.

Practical uses​

  • Recover from an accidental DROP DATABASE or DROP TABLE.
  • Undo a migration script that dropped the wrong table.
  • Bring back a previous database after a deployment created a new one with the same name.
  • Restore a table under a temporary name for an audit, a comparison, or forensic analysis.
  • Make operator cleanup safer: use a normal DROP first, and FORCE later only when you are certain nobody needs the data.

Recovery complements backups; it does not replace them. You still need backups for disaster recovery, long-term retention, and losing a whole cluster or storage volume. A recoverable drop is faster while the data is still present in the same cluster.

Limits​

Recoverable drops apply to root databases and to tables in root databases.

They do not apply to:

  • Dropped columns.
  • Database branches.
  • Tables dropped inside a database branch.
  • Objects dropped with FORCE.
  • Orphans that CamusDB reclaimed after the retention window.

Dropping a database branch removes it immediately. See Database Branching for details on the branch lifecycle.

Errors​

ErrorWhen it happens
CADB0510 OrphanNotFoundA RELINK TO references an orphan id that does not exist, was already recovered, or was reclaimed.
CADB0012 DatabaseAlreadyExistsA CREATE DATABASE ... RELINK TO targets a database name that already exists.
CADB0013 TableAlreadyExistsA CREATE TABLE ... RELINK TO targets a table name that already exists.