--- warning: DO NOT CHANGE THIS MANUALLY, THIS IS GENERATED BY https://github.com/duckdb/community-extensions repository, check README there title: anofox_scenario excerpt: | DuckDB Community Extensions Git-like branching for analytical databases. Attach isolated what-if scenarios as catalogs, edit them with ordinary SQL on copy-on-write delta storage, branch, diff, and merge them back. extension: name: anofox_scenario version: 2026.10.21 description: Git-like branching for analytical databases. Attach isolated what-if scenarios as catalogs, edit them with ordinary SQL on copy-on-write delta storage, branch, diff, and merge them back. language: C++ build: cmake excluded_platforms: "windows_amd64_rtools;windows_amd64_mingw;" license: BSL 1.1 requires_toolchains: "cmake, openssl" maintainers: - jrosskopf repo: github: DataZooDE/anofox-scenario ref: 1813667992e470e4f775e2a5714ed6a23e213821 variegata: 1813667992e470e4f775e2a5714ed6a23e213821 docs: hello_world: | -- History as recorded CREATE TABLE sales_plan (region VARCHAR PRIMARY KEY, units INTEGER); INSERT INTO sales_plan VALUES ('EMEA', 1000), ('AMER', 2000), ('APAC', 500); -- Branch a what-if world: two statements, then it's just SQL CALL scenario_create('aggressive_q4', 'push APAC hard'); ATTACH 'aggressive_q4' AS q4 (TYPE scenario); UPDATE q4.sales_plan SET units = 1500 WHERE region = 'APAC'; DELETE FROM q4.sales_plan WHERE region = 'EMEA'; -- Both worlds coexist; the base is never written SELECT 'base' AS world, * FROM sales_plan UNION ALL SELECT 'scenario', * FROM q4.sales_plan ORDER BY world, region; -- Audit the changes, then promote them SELECT * FROM scenario_diff('aggressive_q4', 'sales_plan'); SELECT * FROM scenario_merge('aggressive_q4'); extended_description: | anofox_scenario brings git-like branching to DuckDB databases. A scenario is an attached catalog (`ATTACH 'name' AS s (TYPE scenario)`) over your existing tables: reads merge the base with the scenario's copy-on-write delta on the fly, and INSERT / UPDATE / DELETE / `MERGE INTO` / `ON CONFLICT` (all with RETURNING) land in the delta — the base tables are never modified. Three isolation tiers: a live overlay (default), `mode := 'materialized'` point-in-time copies, and DuckLake bases pinned to creation time via `AT (TIMESTAMP)` for zero-copy snapshot isolation. Scenarios branch from each other (`from_scenario :=`), inheriting changes, declared row identities, and snapshot pins. A streaming diff engine (`scenario_diff`, `scenario_diff_summary`) audits any world against its origin or another world, and `scenario_merge(name, on_conflict := 'abort'|'ours'|'theirs')` promotes a scenario into its base atomically — with true 3-way drift conflicts when a creation snapshot exists. Views rebind inside scenarios, all base schemas are mirrored, and tables without a primary key work either via `key_columns :=` declared identity or bag semantics with multiplicity tracking. Scenario worlds compose with table-name-driven extensions: for example `ts_forecast_by('s.demand', ...)` (anofox_forecast) forecasts a what-if world directly, no copies needed. The extension collects anonymous usage telemetry (an envelope-only `extension_loaded` event; never table names, keys, or SQL). Disable with `SET anofox_scenario_telemetry_enabled = false` or `DATAZOO_DISABLE_TELEMETRY=1`; see TELEMETRY.md in the repository. extension_star_count: 8 extension_star_count_pretty: 8 extension_download_count: 16747 extension_download_count_pretty: 16.7k image: '/images/community_extensions/social_preview/preview_community_extension_anofox_scenario.png' layout: community_extension_doc --- ### Compatibility Matrix This table covers all DuckDB releases that have not reached [end-of-life](https://duckdb.org/release_calendar), including LTS releases, and shows the 2 most recent patch releases of each. Older patch releases are not listed, but the extension may be available for them as well.
| Platform | 1.4.4 | 1.4.5 | 1.5.5 | 1.5.6 | 2.0.0 | | :--- | :---: | :---: | :---: | :---: | :---: | | Linux AMD64 | ❌ | ❌ | ✅ | ✅ | ✅ | | Linux ARM64 | ❌ | ❌ | ✅ | ✅ | ✅ | | macOS AMD64 | ❌ | ❌ | ✅ | ✅ | ✅ | | macOS ARM64 | ❌ | ❌ | ✅ | ✅ | ✅ | | Windows AMD64 | ❌ | ❌ | ✅ | ✅ | ✅ | | Windows ARM64 | ❌ | ❌ | ❌ | ❌ | ❌ | | WebAssembly | ❌ | ❌ | ✅ | ✅ | ✅ | ### Installing and Loading ```sql INSTALL {{ page.extension.name }} FROM community; LOAD {{ page.extension.name }}; ``` {% if page.docs.hello_world %} ### Example ```sql {{ page.docs.hello_world }}``` {% endif %} {% if page.docs.extended_description %} ### About {{ page.extension.name }} {{ page.docs.extended_description }} {% endif %} ### Added Functions | function_name | function_type | description | comment | examples | |------------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------| | scenario_create | table | Register a scenario. 'materialized' mode copies every base table, the default 'delta' mode stores only what changed; from_scenario branches off an existing scenario; base uses another attached catalog; key_columns declares row identity for tables without a primary key. | NULL | [CALL scenario_create('optimistic');] | | scenario_create | table | Register a scenario. 'materialized' mode copies every base table, the default 'delta' mode stores only what changed; from_scenario branches off an existing scenario; base uses another attached catalog; key_columns declares row identity for tables without a primary key. | NULL | [CALL scenario_create('price_increase', 'Analyzing 10% price increase impact');] | | scenario_diff | table | Diff a scenario against its origin, returning the key columns (every column for keyless tables) plus change_type ('added', 'removed' or 'modified'), column_name, old_value and new_value. | NULL | [SELECT * FROM scenario_diff('price_increase', 'products');] | | scenario_diff | table | Diff any two sides against each other -- 'main' or any scenario name -- where old_value comes from side a and new_value from side b. | NULL | [SELECT * FROM scenario_diff('main', 'price_increase', 'products');] | | scenario_diff_summary | table | Summarise a scenario's changes per table as rows_added, rows_modified and rows_removed. | NULL | [SELECT * FROM scenario_diff_summary('price_increase');] | | scenario_drop | table | Remove a scenario and its delta or materialized tables. Refuses while the scenario is attached or while branches of it still exist. | NULL | [CALL scenario_drop('price_increase_eu');] | | scenario_freeze | table | Reject writes to a scenario while leaving reads working; a frozen materialized scenario is a snapshot. | NULL | [CALL scenario_freeze('q2_approved');] | | scenario_list | table | List every registered scenario as (scenario_id, name, mode, frozen, parent, created_at, description). | NULL | [SELECT * FROM scenario_list();] | | scenario_merge | table | Apply a scenario's changes back to its base tables. | NULL | [SELECT * FROM scenario_merge('price_increase', on_conflict := 'abort');] | | scenario_merge_preview | table | Show the actions a merge would take as (table_name, key, action, conflict). Streaming, with no side effects. | NULL | [SELECT * FROM scenario_merge_preview('price_increase');] | | scenario_migrate | table | Migrate a legacy v0.1 scenario database into the v2 layout. One-way. | NULL | [SELECT * FROM scenario_migrate();] | | scenario_refresh | table | Deprecated: tables added to the base after scenario_create are writable without it. Only declares key_columns for keyless tables the scenario does not track yet. | NULL | [SELECT * FROM scenario_refresh('price_increase');] | | scenario_unfreeze | table | Allow writes to a scenario again, reversing scenario_freeze. | NULL | [CALL scenario_unfreeze('q2_approved');] | ### Overloaded Functions This extension does not add any function overloads. ### Added Types This extension does not add any types. ### Added Settings | name | description | input_type | scope | aliases | typed_value | |----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------|---------|-------------| | anofox_scenario_suppression_hash_limit | Maximum number of updated/deleted scenario keys per table for which scans suppress base rows through an in-memory hash set instead of per-row delta index probes | UBIGINT | GLOBAL | [] | 4194304 | | anofox_scenario_telemetry_enabled | Enable or disable anonymous usage telemetry for anofox_scenario | BOOLEAN | GLOBAL | [] | true | | datazoo_banner | Show the DataZoo feedback banner when an extension is loaded in an interactive terminal (at most once a day per extension). | BOOLEAN | GLOBAL | [] | true | | temp_directory | Set the directory to which temporary files are written. | VARCHAR | GLOBAL | [] | post.db.tmp |