# SQL RecycleBin — Complete Technical Documentation & Case Studies (GEO / LLM Full Context) Powered By 92 Logics (https://www.92logics.com) | Created by Qaiser Mughal (qaiser@92logics.com) Website: https://sqlrecyclebin.com | GitHub: https://github.com/qmmughal/sql-recyclebin --- ## 1. What Problem Does SQL RecycleBin Solve? Oracle has provided `AS OF TIMESTAMP` Flashback Query for decades. Microsoft SQL Server lacks a built-in, lightweight row-level "undo" command across all editions. When an engineer or DBA accidentally runs a `DELETE` without a `WHERE` clause or a mass `UPDATE` that overwrites a column on a live SQL Server database, traditional recovery options have severe drawbacks: 1. **Point-in-time database restore:** Slow (minutes to hours for multi-hundred-GB databases) and lossy (destroys every transaction after the timestamp unless restored to a sidecar server and manually merged with `IDENTITY_INSERT`). 2. **Third-party transaction log forensics tools:** Expensive ($2,000+ per seat) and ineffective if the database is in `SIMPLE` recovery mode and a checkpoint has truncated the log. 3. **Custom shadow audit tables:** Brittle—they break or fail to capture new columns whenever developers run `ALTER TABLE`. **SQL RecycleBin** solves this by installing a self-contained `rb` schema (`install.sql`). Once enabled on a table (`EXEC rb.Enable @Table = 'dbo.Orders'`), every `DELETE` and `UPDATE` is captured as compressed JSON in `rb.ChangeLog`. You can query deleted rows as typed columns (`EXEC rb.Deleted`) and undo mistakes with one command (`EXEC rb.UndoLast`). --- ## 2. Internal Architecture (`install.sql`) 1. **Storage (`rb.ChangeLog`):** - Columns: `ChangeId BIGINT IDENTITY`, `SchemaName SYSNAME`, `TableName SYSNAME`, `Operation CHAR(1)` (`'D'` or `'U'`), `TxId BIGINT` (`CURRENT_TRANSACTION_ID()`), `KeyValues NVARCHAR(1000)` (PK as JSON), `RowBefore NVARCHAR(MAX)` (full row before change as JSON), `RowAfter NVARCHAR(MAX)` (full row after update as JSON), `ChangedBy SYSNAME` (`ORIGINAL_LOGIN()`), `AppName NVARCHAR(128)` (`APP_NAME()`), `HostName NVARCHAR(128)` (`HOST_NAME()`), `ChangedAt DATETIME2(3)` (`SYSUTCDATETIME()`), `Restored BIT`. - Rebuilt with `DATA_COMPRESSION = PAGE` (supported on all editions since SQL Server 2016 SP1, including Express). 2. **Dynamic Metadata & Schema Resilience (`rb.internal_GetTableMeta`):** - Queries `sys.columns`, `sys.types`, and `sys.indexes` at runtime to build `OPENJSON` `WITH (...)` column definitions, insertable column lists (skipping computed and `rowversion`/`timestamp` columns), `UPDATE SET` clauses, primary key join predicates, and `@HasIdentity` detection. - Because rows are stored as JSON (`FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES`), running `ALTER TABLE` never breaks the trigger or recovery procedures. 3. **Surgical Undo (`rb.UndoTransaction` / `rb.UndoLast` / `rb.Restore`):** - Sets `EXEC rb.BypassOn;` (`SESSION_CONTEXT(N'rb_bypass') = 1`) so the undo operation itself does not re-trigger capture. - If the table has an `IDENTITY` column (`@HasIdentity = 1`), dynamically wraps the `INSERT` in `SET IDENTITY_INSERT