Skip to content

dumpling: support column filters for table exports - #70196

Merged
ti-chi-bot[bot] merged 41 commits into
pingcap:masterfrom
joechenrh:dumpling-column-filter-internal
Aug 6, 2026
Merged

ti-chi-bot[bot] merged 41 commits into
pingcap:masterfrom
joechenrh:dumpling-column-filter-internal

Conversation

@joechenrh

@joechenrh joechenrh commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #70255

Problem Summary:

Cloud Export needs a backend-facing Dumpling primitive to support table-level column filtering so data files can omit selected columns while keeping existing table selection, split-key selection, and metadata behavior correct.

What changed and how does it work?

This PR adds Dumpling column filter inputs for data output projection. This is a backend-facing Dumpling interface while Cloud Export uses Dumpling, not a customer-facing Cloud API contract.

File form:

[[filters]]
matcher = ["app.orders", "app.customers"]
columns = ["id", "customer_id", "amount"]

[[filters]]
matcher = ["app.audit_*"]
columns = ["*", "!phone_number", "!id_number", "!debug_blob"]

Inline CLI form:

dumpling -m \
  --column-filter '{ matcher = ["app.orders", "app.customers"], columns = ["id", "customer_id", "amount"] }' \
  --column-filter '{ matcher = ["app.audit_*"], columns = ["*", "!phone_number", "!id_number", "!debug_blob"] }'

Both forms compile into the same filter rules. --column-filter can be specified multiple times and is mutually exclusive with --column-filter-file.

The matching rules follow TiCDC column selectors and Lightning table filters:

  • table matchers use the existing table-filter syntax;
  • column rules reuse the table-filter column rule parser, including wildcard and ! exclusion rules;
  • rules are evaluated with later entries taking priority;
  • once a table has matching column rules, columns that do not match any positive rule are not selected, so exclude-only filters should be written as columns = ["*", "!col_to_skip"].

When multiple [[filters]] entries or inline --column-filter rules match the same table, later filters have higher priority, matching the existing filter rule behavior.

The column filter is applied during a pre-dump column projection preparation step. Dumpling stores both source columns/types and selected columns/types per table:

  • data SELECT uses the selected projection;
  • split-key and source-column metadata keep using the source table columns;
  • generated columns remain excluded from writable source columns as before;
  • views and sequences are not column-filtered.

The option is currently guarded to data-only table dumps: --column-filter and --column-filter-file require --no-schemas/-m and cannot be used together with --sql.

Check List

Tests

  • Unit test
    • Added/updated coverage for column filter parsing, column indexes, precomputed column projection, generated-column handling, view handling, and split-key source columns.
    • ./tools/check/failpoint-go-test.sh dumpling/export -count=1
    • go test ./pkg/util/table-filter -count=1
  • Integration test
  • Manual test (add detailed scripts or steps below)
    • git diff --check
  • No need to test
    • I checked and no code files have been changed.

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

Please refer to Release Notes Language Style Guide to write a quality release note.

None

@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-linked-issue release-note-none Denotes a PR that doesn't merit a release note. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. component/dumpling This is related to Dumpling of TiDB. labels Jul 29, 2026
@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Column projection is replaced with JSON-driven column filtering. The CLI, configuration, validation, SQL generation, and dump metadata now use ColumnFilterConfig, while source column metadata remains available separately from selected output metadata.

Changes

Column filter export

Layer / File(s) Summary
Filter model and CLI configuration
dumpling/export/column_filter.go, dumpling/export/config.go, dumpling/export/config_test.go, dumpling/export/BUILD.bazel
Adds compiled matcher-based column filters, renames the CLI option to --column-filter-file, updates configuration parsing, and tests JSON and flag behavior.
SQL projection and source metadata
dumpling/export/sql.go, dumpling/export/sql_test.go, dumpling/export/ir.go, dumpling/export/ir_impl.go
Builds filtered output and unfiltered source fields, exposes source column names and types, and uses source metadata for key and numeric-index lookup.
Dump validation and metadata integration
dumpling/export/dump.go, dumpling/export/dump_test.go, dumpling/export/util_for_test.go
Validates filters before dumping and preserves source metadata while applying filtered output metadata during table construction.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Config
  participant Dumper
  participant SQLProjection
  participant TableMeta
  CLI->>Config: provide --column-filter-file
  Config->>Config: parse and compile JSON rules
  Config->>Dumper: provide ColumnFilterConfig
  Dumper->>SQLProjection: validate and apply filter
  SQLProjection->>TableMeta: store selected and source metadata
  TableMeta-->>Dumper: return dump metadata
Loading

Poem

I’m a rabbit with filters, hopping through rows,
Keeping the columns that each table shows.
Source names stay safe while outputs grow neat,
JSON rules guide every database beat.
CLI flags thump, and tests cheer: “Complete!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: adding column filter support for Dumpling table exports.
Description check ✅ Passed The description includes the issue number, problem, implementation details, tests, side effects, documentation impact, and release note.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 14.28571% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.0638%. Comparing base (8512729) to head (b0956d7).
⚠️ Report is 117 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #70196        +/-   ##
================================================
- Coverage   76.3227%   73.0638%   -3.2589%     
================================================
  Files          2041       2078        +37     
  Lines        560306     604649     +44343     
================================================
+ Hits         427641     441780     +14139     
- Misses       131764     160875     +29111     
- Partials        901       1994      +1093     
Flag Coverage Δ
integration 40.7774% <0.0000%> (+1.0721%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 60.4136% <33.3333%> (-0.0335%) ⬇️
parser ∅ <ø> (∅)
br 44.8312% <ø> (-17.8901%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dumpling/export/column_selector.go`:
- Around line 121-131: The include-mode validation and unmatchedColumns flow
currently report normalized lowercase names instead of the column casing
supplied by the user. Preserve the original selector casing alongside the
lowercase matching keys in selector.columnSet, then use those original names
when constructing unmatchedColumns and the “included columns” error while
retaining case-insensitive matching.

In `@dumpling/export/dump.go`:
- Around line 265-271: Add the same column-selectors/no-schemas validation used
by config.ParseFromFlags to Dump() before validateColumnSelectors runs. When
conf.SQL is empty and conf.ColumnSelectors is non-nil, reject configurations
where NoSchemas is not enabled, while preserving the existing selector
validation and error propagation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b2e820e0-8073-4d13-9d68-a05110fe1610

📥 Commits

Reviewing files that changed from the base of the PR and between ab79433 and 0d1ba76.

📒 Files selected for processing (11)
  • dumpling/export/BUILD.bazel
  • dumpling/export/column_selector.go
  • dumpling/export/config.go
  • dumpling/export/config_test.go
  • dumpling/export/dump.go
  • dumpling/export/dump_test.go
  • dumpling/export/ir.go
  • dumpling/export/ir_impl.go
  • dumpling/export/sql.go
  • dumpling/export/sql_test.go
  • dumpling/export/util_for_test.go

Comment thread dumpling/export/column_selector.go Outdated
Comment thread dumpling/export/dump.go Outdated
@ingress-bot

Copy link
Copy Markdown

🔍 Starting code review for this PR...

@joechenrh

Copy link
Copy Markdown
Contributor Author

/retest

ingress-bot

This comment was marked as outdated.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
dumpling/export/config_test.go (1)

103-107: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make the case-sensitive assertion observable.

With only c1, both a selector match and a case-sensitive table-matcher miss return the same result. Include an unselected column and assert it remains present when DB1.T1 does not match db1.t1.

Proposed test adjustment
-	selectedFields, err = selectors.applyToColumns("DB1", "T1", []string{"c1"})
+	selectedFields, err = selectors.applyToColumns("DB1", "T1", []string{"c1", "c3"})
 	require.NoError(t, err)
-	require.Equal(t, []string{"c1"}, selectedFields)
+	require.Equal(t, []string{"c1", "c3"}, selectedFields)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dumpling/export/config_test.go` around lines 103 - 107, Update the test
around selectors.applyToColumns to include both a selected column and an
unselected column in the input, then assert the unselected column remains when
applying selectors to “DB1.T1” while the selector targets lowercase “db1.t1”.
This makes the case-sensitive table-matcher miss observable while preserving the
existing no-error assertions.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@dumpling/export/config_test.go`:
- Around line 103-107: Update the test around selectors.applyToColumns to
include both a selected column and an unselected column in the input, then
assert the unselected column remains when applying selectors to “DB1.T1” while
the selector targets lowercase “db1.t1”. This makes the case-sensitive
table-matcher miss observable while preserving the existing no-error assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 350cf15e-e16a-4bac-8f60-379da3a002f5

📥 Commits

Reviewing files that changed from the base of the PR and between 0d1ba76 and 38e1d1f.

📒 Files selected for processing (4)
  • dumpling/export/column_selector.go
  • dumpling/export/config_test.go
  • dumpling/export/dump_test.go
  • dumpling/export/sql_test.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
dumpling/export/dump.go (1)

265-270: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Avoid the duplicate metadata sweep while consistency locks are held.

Validation runs before TearDown, issuing serial SHOW COLUMNS calls for every base table; dumpTableMeta fetches the same metadata again. Large lock/flush dumps therefore extend the source write-block window by a full extra schema sweep.

  • dumpling/export/dump.go#L265-L270: run validation only after the consistency lock is released, while still before tasks are submitted, or reuse cached metadata.
  • dumpling/export/dump.go#L505-L516: cache or propagate writable-column metadata so validation and table-meta construction do not issue duplicate queries.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dumpling/export/dump.go` around lines 265 - 270, The validation at
dumpling/export/dump.go:265-270 currently performs a full metadata sweep while
consistency locks are held; move validateColumnFilter out of the locked phase
and run it after TearDown but before task submission. At
dumpling/export/dump.go:505-516, avoid re-querying the same writable-column
metadata by caching or propagating the metadata between validation and
dumpTableMeta, preserving validation behavior while eliminating duplicate SHOW
COLUMNS calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dumpling/export/config.go`:
- Around line 635-640: Enforce the column-filter mode contract at all affected
sites: in dumpling/export/config.go lines 635-640, reject a non-nil ColumnFilter
when SQL is non-empty in addition to the existing NoSchemas validation; in
dumpling/export/dump.go lines 265-270, add an independent early rejection for
ColumnFilter when either NoSchemas is false or SQL is non-empty before
consistency setup; in dumpling/export/config_test.go lines 135-141, update the
SQL-and-filter case to expect the incompatibility error.

In `@dumpling/export/dump.go`:
- Around line 1361-1364: Update dumpTableMeta so conf.ColumnFilter is supplied
to buildSelectFieldInfo only when table represents a base table. For views and
sequences, pass the unfiltered/empty filter value so matching include or exclude
rules are not applied after validation. Reuse the existing table-type
classification from TableInfo rather than changing validation behavior.

---

Duplicate comments:
In `@dumpling/export/dump.go`:
- Around line 265-270: The validation at dumpling/export/dump.go:265-270
currently performs a full metadata sweep while consistency locks are held; move
validateColumnFilter out of the locked phase and run it after TearDown but
before task submission. At dumpling/export/dump.go:505-516, avoid re-querying
the same writable-column metadata by caching or propagating the metadata between
validation and dumpTableMeta, preserving validation behavior while eliminating
duplicate SHOW COLUMNS calls.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cba590e8-3af6-4ea8-add8-f56d50dc73ce

📥 Commits

Reviewing files that changed from the base of the PR and between 38e1d1f and 0d7760e.

📒 Files selected for processing (7)
  • dumpling/export/column_filter.go
  • dumpling/export/config.go
  • dumpling/export/config_test.go
  • dumpling/export/dump.go
  • dumpling/export/dump_test.go
  • dumpling/export/sql.go
  • dumpling/export/sql_test.go

Comment thread dumpling/export/config.go Outdated
Comment thread dumpling/export/dump.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
dumpling/export/config.go (1)

636-641: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Enforce the column-filter mode contract at both boundaries.

SQL-mode dumps ignore ColumnFilter, while directly constructed Config values can still combine filtering with schema output. Reject filters with SQL != "" during parsing and again at Dump() entry before consistency setup.

  • dumpling/export/config.go#L636-L641: reject ColumnFilter when conf.SQL != "" as well as when !conf.NoSchemas.
  • dumpling/export/dump.go#L265-L269: independently reject ColumnFilter when schemas are enabled or SQL mode is selected.
Proposed fix
- if conf.ColumnFilter != nil && !conf.NoSchemas {
-     return errors.New("--column-filter-file requires --no-schemas/-m")
+ if conf.ColumnFilter != nil && (!conf.NoSchemas || conf.SQL != "") {
+     return errors.New("--column-filter-file requires --no-schemas/-m and cannot be used with --sql")
  }
+ if conf.ColumnFilter != nil && (!conf.NoSchemas || conf.SQL != "") {
+     return errors.New("column filter requires schema-less table dumping and cannot be used with SQL mode")
+ }
  baseConn := newBaseConn(metaConn, true, rebuildMetaConn)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dumpling/export/config.go` around lines 636 - 641, Enforce the column-filter
contract at both validation boundaries: in dumpling/export/config.go within the
ParseColumnFilterFile handling, reject non-nil conf.ColumnFilter when either
conf.SQL is non-empty or schemas are enabled; in dumpling/export/dump.go at
Dump() entry, independently reject the same two incompatible states before
consistency setup. Preserve the existing error behavior and ensure directly
constructed Config values are validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@dumpling/export/config.go`:
- Around line 636-641: Enforce the column-filter contract at both validation
boundaries: in dumpling/export/config.go within the ParseColumnFilterFile
handling, reject non-nil conf.ColumnFilter when either conf.SQL is non-empty or
schemas are enabled; in dumpling/export/dump.go at Dump() entry, independently
reject the same two incompatible states before consistency setup. Preserve the
existing error behavior and ensure directly constructed Config values are
validated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0eb68276-0a94-4720-bfaf-3c1b7d986137

📥 Commits

Reviewing files that changed from the base of the PR and between 0d7760e and 6de490d.

📒 Files selected for processing (6)
  • dumpling/export/config.go
  • dumpling/export/dump.go
  • dumpling/export/dump_test.go
  • dumpling/export/ir.go
  • dumpling/export/sql.go
  • dumpling/export/sql_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • dumpling/export/dump_test.go
  • dumpling/export/sql_test.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
dumpling/export/dump.go (1)

1394-1411: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reset err after logging the harmless missing _tidb_rowid check.

SelectTiDBRowID runs for TiDB sources even for views and sequences, and only the ErrBadField path returns nil. For non-base tables, the later GetColumnTypes block is skipped, so any other error remains in err and is returned from dumpTableMeta.

🐛 Proposed fix: reset `err` after logging the swallowed failure
 	if conf.ServerInfo.ServerType == version.ServerTypeTiDB {
 		hasImplicitRowID, err = SelectTiDBRowID(tctx, conn, db, tbl)
 		if err != nil {
 			tctx.L().Info("check implicit rowID failed", zap.String("database", db), zap.String("table", tbl), log.ShortError(err))
+			err = nil
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dumpling/export/dump.go` around lines 1394 - 1411, In dumpTableMeta, clear
err after logging a SelectTiDBRowID failure that is intentionally ignored, so
non-base tables do not return the stale error when GetColumnTypes is skipped.
Preserve the existing logging and subsequent GetColumnTypes error handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@dumpling/export/dump.go`:
- Around line 1394-1411: In dumpTableMeta, clear err after logging a
SelectTiDBRowID failure that is intentionally ignored, so non-base tables do not
return the stale error when GetColumnTypes is skipped. Preserve the existing
logging and subsequent GetColumnTypes error handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a08646c0-c8b1-4136-938b-3fc0e5b0ddcc

📥 Commits

Reviewing files that changed from the base of the PR and between 6de490d and b9d1f4b.

📒 Files selected for processing (3)
  • dumpling/export/dump.go
  • dumpling/export/dump_test.go
  • dumpling/export/sql.go

@joechenrh joechenrh changed the title dumpling: add column filter file for table exports dumpling: support column filters for table exports Aug 4, 2026

@ingress-bot ingress-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This review was generated by AI and should be verified by a human reviewer.
Manual follow-up is recommended before merge.

Summary

  • Total findings: 6
  • Inline comments: 6
  • Summary-only findings (no inline anchor): 0
Findings (highest risk first)

🟡 [Minor] (4)

  1. ParseColumnFilter now leaks the concrete rule slice instead of the ColumnFilter interface (pkg/util/table-filter/column_filter.go:34, pkg/util/table-filter/column_filter.go:29, dumpling/export/column_filter.go:119)
  2. Column-filter TOML is decoded permissively, so a misspelled columns key silently dumps all columns (dumpling/export/column_filter.go:31, dumpling/export/column_filter.go:79, dumpling/export/column_filter.go:94)
  3. columnFilterConfig.compile exists only to serve test code (dumpling/export/column_filter.go:40, dumpling/export/config_test.go:69, dumpling/export/config_test.go:236)
  4. --column-filter help text omits the always-case-insensitive column matching contract documented for --column-filter-file (dumpling/export/config.go:388, dumpling/export/config.go:390)

ℹ️ [Info] (2)

  1. parseColumnFilterArgs' TOML re-wrapping trick has no comment explaining the singular "filter" key (dumpling/export/column_filter.go:76)
  2. ColumnFilter interface becomes an unused, confusingly-similar name next to the new ColumnFilterRules (pkg/util/table-filter/column_filter.go:23, pkg/util/table-filter/column_filter.go:34)

Comment thread pkg/util/table-filter/column_filter.go Outdated
Comment thread dumpling/export/column_filter.go Outdated
Comment thread dumpling/export/column_filter.go Outdated
Comment thread dumpling/export/config.go Outdated
Comment thread dumpling/export/column_filter.go Outdated
Comment thread pkg/util/table-filter/column_filter.go
@joechenrh
joechenrh force-pushed the dumpling-column-filter-internal branch from bfe3701 to 7d17b31 Compare August 4, 2026 05:58

@D3Hunter D3Hunter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness and test-sufficiency review: I found one fail-open data-selection bug, one exported-API compatibility concern, and one metadata-query retry regression. The current tests pass but are not sufficient to cover these cases or the final SQL/CSV/Parquet output workflow.

Comment thread dumpling/export/column_filter.go Outdated
columnRules := c.matchColumnRules(database, table)

selectedIndexes := make([]int, 0, len(sourceColumns))
if len(columnRules) == 0 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Empty or omitted column rules fail open. compileForOption accepts a matched filter with columns omitted or empty, so matchColumnRules returns a zero-length list. This branch then treats it exactly like an unmatched table and exports every writable column. That contradicts #70255, which says that once a table matches, columns not matching a positive rule are not selected; for a projection intended to omit sensitive fields, an incomplete rule can therefore expose all columns. Please reject empty column lists during compilation, or return a separate matched flag so a matched empty rule reaches the existing no-writable-columns error. Add file and inline tests for both omitted columns and columns = [], and replace the current matcher-only test that expects all columns.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 327c14b . compileForOption now rejects omitted or empty columns for both inline and file rules, and the old matcher-only all-columns case was replaced with coverage for both invalid forms.

Comment thread dumpling/export/ir.go Outdated
ColumnTypes() []string
// ColumnNames returns the selected output column names.
ColumnNames() []string
// SourceColumnTypes returns all source writable column types for schema-based logic such as split keys.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Avoid breaking the exported metadata/parser contracts for this internal feature. Adding these methods to exported TableMeta makes every downstream implementation stop compiling. This PR also changes ParseColumnFilter from returning ColumnFilter to concrete ColumnFilterRules, which breaks consumers that retain the old function signature. Neither break is necessary for the backend-facing CLI feature: keep the existing TableMeta interface and use a private extended source-metadata interface/carrier internally, and preserve ParseColumnFilter(args) (ColumnFilter, error) while adding a separate composable rules API for Dumpling.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed the compatibility-sensitive parts in 327c14b . ParseColumnFilter keeps the old (ColumnFilter, error) signature, and Dumpling uses ParseColumnFilterRules when it needs ordered rules. The source-column access also moved off TableMeta into a private extension path. I restored the existing Dumpling writer contracts in cc21813 and cab8d16 instead of adding private adapter layers around ColumnInfos and GetRawBytes, since those interfaces already carried that metadata before this PR.

Comment thread dumpling/export/sql.go
err := db.QuerySQL(tctx, func(rows *sql.Rows) error {
err := db.queryRows(tctx, func(rows *sql.Rows) error {
var err error
colTypes, err = rows.ColumnTypes()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Propagate Rows.Close errors so metadata discovery can retry. This reads ColumnTypes() without advancing the LIMIT 1 result to EOF. queryRows checks rows.Err() before its deferred close, and the deferred rows.Close() return value is discarded; the previous implementation explicitly returned that close error. If the driver discovers a protocol/network failure while draining the unread row during close, this attempt is reported as successful and the connection is not reset/rebuilt. Please close explicitly before returning success, propagate the close error, then inspect rows.Err(). A sqlmock.Rows.CloseError regression test can pin the retry/error behavior.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 327c14b . GetColumnTypes now closes rows explicitly before returning success and propagates close or rows errors through the existing retry path. Added TestGetColumnTypesRetriesCloseError with sqlmock.Rows.CloseError to pin the behavior.

Comment thread dumpling/export/dump.go
)
tctx, conf, pool := d.tctx, d.conf, d.dbHandle
tctx.L().Info("begin to run Dump", zap.Stringer("conf", conf))
if len(conf.columnFilter.Filters) > 0 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This validation appears redundant with Config.ParseFromFlags, where both --column-filter and --column-filter-file already call validateColumnFilterOptions. Please either remove this duplicate check, or add a short comment explaining why it must also be enforced at Dump() time—for example, because NewDumper retains the caller-owned *Config, whose exported SQL and NoSchemas fields can be mutated after parsing or construction. If the runtime guard is retained, it should use source-neutral wording rather than always passing flagColumnFilterFile, which can mislabel an inline --column-filter configuration.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept the runtime guard and added a one-line comment in 327c14b . The guard is still needed because Dumpling can receive a Config built or mutated without ParseFromFlags. I kept it on validateColumnFilterOptions rather than adding a second validator just to customize the message, so the runtime path still reuses the same precondition logic as CLI parsing.

Comment thread dumpling/export/sql.go
type columnProjection struct {
sourceTypes []*sql.ColumnType
selectedTypes []*sql.ColumnType
selectField string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we rename this to selectList? “Select list” is the standard SQL grammar term for the fragment between SELECT and FROM, so it is more precise than the singular selectField and does not sound like a complete SQL statement. I would avoid selectListSQL for that reason. The resulting code also reads naturally: projection.selectList = "*" or projection.selectList = strings.Join(selectedFields, ","). This can remain an internal rename without changing the exported TableMeta method in this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left this as selectField after another pass. It is not the pure SQL grammar term, but it matches the existing TableMeta.SelectedField() naming and the surrounding code treats it as the rendered comma-joined field string. Keeping the local name aligned with that API avoids churn in this PR.

@D3Hunter D3Hunter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add some integration test under dumpling/tests

rest lgtm

@OliverS929 OliverS929 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rest LGTM.

Comment thread dumpling/export/dump.go
Comment thread dumpling/export/column_filter.go
Comment thread dumpling/export/dump.go
@ti-chi-bot ti-chi-bot Bot added the needs-1-more-lgtm Indicates a PR needs 1 more LGTM. label Aug 4, 2026
@ti-chi-bot

ti-chi-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: D3Hunter, OliverS929

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot Bot added approved lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Aug 6, 2026
@ti-chi-bot

ti-chi-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

[LGTM Timeline notifier]

Timeline:

  • 2026-08-04 14:32:42.177003288 +0000 UTC m=+2538548.213098344: ☑️ agreed by OliverS929.
  • 2026-08-06 08:51:39.485865465 +0000 UTC m=+2690885.521960631: ☑️ agreed by D3Hunter.

@ti-chi-bot
ti-chi-bot Bot merged commit 3a5407d into pingcap:master Aug 6, 2026
37 checks passed
@joechenrh
joechenrh deleted the dumpling-column-filter-internal branch August 6, 2026 09:33
joechenrh added a commit to ti-chi-bot/tidb that referenced this pull request Sep 16, 2026
…quisite

Include the prerequisite column filtering changes from pingcap#70196 with pingcap#70506, resolve committed cherry-pick conflict markers, and preserve release-branch writer interfaces.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved component/dumpling This is related to Dumpling of TiDB. lgtm release-note-none Denotes a PR that doesn't merit a release note. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dumpling: support column filtering for table data exports

4 participants