Skip to content

feat: add data lineage#20198

Open
youngsofun wants to merge 6 commits into
databendlabs:mainfrom
youngsofun:codex/lineage-meta-storage
Open

feat: add data lineage#20198
youngsofun wants to merge 6 commits into
databendlabs:mainfrom
youngsofun:codex/lineage-meta-storage

Conversation

@youngsofun

@youngsofun youngsofun commented Jul 24, 2026

Copy link
Copy Markdown
Member

I hereby agree to the terms of the CLA available at: https://docs.databend.com/dev/policies/cla/

Summary

This PR adds persistent object-level and column-level data lineage, lifecycle handling, and the Enterprise GET_LINEAGE table function.

Related PRs

The remaining changes stay together because the metadata schema, metadata API, persistence paths, lifecycle behavior, GET_LINEAGE, and SQL workflow tests share the same identity and column-mapping contract. Intermediate subsets would not provide a complete or meaningfully testable user workflow.

Reviewing commit by commit is recommended:

  1. Extract query lineage (temporary duplicate of feat(query): extract query lineage from plans #20201 until it merges).
  2. Add the lineage metadata schema and protobuf compatibility.
  3. Add metadata list, merge, replace, and lifecycle APIs.
  4. Add the GET_LINEAGE table function.
  5. Persist structural and DML lineage.
  6. Add end-to-end SQL workflow tests.

This PR persists lineage for:

  • CREATE VIEW
  • CREATE TABLE ... AS SELECT ... (CTAS)
  • INSERT ... SELECT
  • REPLACE INTO ... SELECT
  • multi-table insert
  • UPDATE ... FROM
  • MERGE

COPY INTO persistence hooks are prepared, but extraction of Plan::CopyIntoTable sources is not included yet.

Motivation

Databend currently has no persistent metadata representation for tracing where tables and columns originate or where their data flows. This PR adds persistent bidirectional lineage metadata, column-level mappings, and a Snowflake-style GET_LINEAGE table function.

Lineage model

A lineage edge always follows the canonical direction:

upstream object/column -> downstream object/column

Objects with stable table IDs use ID-addressed lineage. Name-addressed lineage is used for name-bound dependencies, including view references and tables without stable lineage IDs.

Views form a lineage boundary: DML reading from a view records the view rather than expanding directly to its base tables. Streams behave differently: stream data columns are attributed to the base table, while stream metadata columns are ignored.

Self-referential writes do not create lineage loops. For example, INSERT INTO t SELECT * FROM t does not create a t -> t edge.

Metadata and persistence

Each edge is stored in both directions under a tenant-scoped structured key. Structured key encoding provides escaping for object names and integrates with metactl, snapshots, backups, and tenant export/filter tooling.

Structural lineage is committed atomically with object metadata for CREATE VIEW and CTAS. DML lineage is persisted after a successful table commit using a best-effort callback; lineage write failures do not change a successful DML result.

DML merge operations preserve the existing lineage kind, update the last query metadata, and merge column edges without duplicates. Lineage metadata does not currently use TTL.

GET_LINEAGE

GET_LINEAGE is implemented as a table function:

GET_LINEAGE(
    '<object_name>',
    '<object_domain>',
    '<direction>'
    [, distance]
)

Supported domains are TABLE, VIEW, COLUMN, and STAGE. Supported directions are UPSTREAM and DOWNSTREAM; distance defaults to 5 and must be between 1 and 5.

The implementation uses a distance-ordered BFS. Metadata listing and object resolution are concurrent within each level, while levels remain sequential to preserve distance semantics. Query-time resolution validates the current object and column state.

GET_LINEAGE is gated by the Enterprise Feature::Lineage license feature.

Capture configuration

Capture is controlled independently from the Enterprise license:

[query.lineage]
capture_enabled = true

The default is false. This allows deployments that need lineage to opt into its planning and metadata costs. Capture remains stable across license changes, while querying through GET_LINEAGE requires the Enterprise feature.

Object lifecycle

  • Rename and undrop do not rewrite lineage metadata.
  • ID-addressed lineage survives rename and resolves to the current name.
  • Name-addressed lineage becomes temporarily unavailable after rename and recovers if the original name is restored.
  • Dropped views and transient tables remove their lineage.
  • Dropped Fuse tables are filtered during queries and cleaned during GC/vacuum.
  • Temporary, MEMORY, DELTA, and unsupported engines are skipped.
  • Iceberg and Hive tables use name-addressed lineage.
  • Stream lineage passes through to the source table.

Current limitations

  • COPY INTO source lineage extraction is not implemented yet.
  • Materialized view persistence is not connected yet.
  • Existing views created before capture is enabled are not backfilled.
  • Stream is not exposed as a GET_LINEAGE domain because lineage passes through to its base table.
  • Explicit AS MATERIALIZED CTE lineage is not included yet.
  • Historical cleanup and administrative retention policies are not included.

Tests

  • Unit Test
  • Logic Test
  • Benchmark Test
  • No Test - Explain why

Coverage includes metadata key encoding, protobuf compatibility, lineage API behavior, BFS traversal, column propagation, CTAS, views, DML workflows, multi-table insert, rename/drop/undrop behavior, vacuum cleanup, cross-database ID resolution, self-writes, filter-only columns, aggregate expressions, CTEs, subqueries, and stream passthrough.

Type of change

  • Bug Fix (non-breaking change which fixes an issue)
  • New Feature (non-breaking change which adds functionality)
  • Breaking Change (fix or feature that could cause existing functionality not to work as expected)
  • Documentation Update
  • Refactoring
  • Performance Improvement
  • Other (please describe):

This change is Reviewable

@youngsofun
youngsofun requested a review from drmingdrmer as a code owner July 24, 2026 04:25
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@github-actions github-actions Bot added the pr-feature this PR introduces a new feature to the codebase label Jul 24, 2026
@youngsofun
youngsofun marked this pull request as draft July 24, 2026 04:28
@youngsofun
youngsofun force-pushed the codex/lineage-meta-storage branch 4 times, most recently from 9997af8 to a5def34 Compare July 24, 2026 09:14
@youngsofun
youngsofun force-pushed the codex/lineage-meta-storage branch from a5def34 to f46b5bc Compare July 24, 2026 09:45
@youngsofun
youngsofun marked this pull request as ready for review July 24, 2026 22:37
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@youngsofun
youngsofun force-pushed the codex/lineage-meta-storage branch from f46b5bc to a01e1f0 Compare July 24, 2026 22:50
@youngsofun
youngsofun force-pushed the codex/lineage-meta-storage branch from a01e1f0 to 74e7d45 Compare July 24, 2026 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-feature this PR introduces a new feature to the codebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant