Skip to content

expression: add column masking related builtins functions - #68321

Open
tiancaiamao wants to merge 14 commits into
pingcap:masterfrom
tiancaiamao:phase9-builtins-on-master
Open

tiancaiamao wants to merge 14 commits into
pingcap:masterfrom
tiancaiamao:phase9-builtins-on-master

Conversation

@tiancaiamao

@tiancaiamao tiancaiamao commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: ref #65744, close #67224

Problem Summary:

pr/phase9-builtins was stacked on top of other masking phases, making direct merge/rebase to latest master conflict-prone.
This PR ports only the masking builtins phase onto current master and aligns behavior with the implementation in issue-bundle-67218-67224.

What changed and how does it work?

  • Add masking builtins in expression layer:
    • MASK_FULL(col[, mask_char])
    • MASK_NULL(col)
    • MASK_PARTIAL(col, preserve_left, preserve_right, mask_char)
    • MASK_DATE(col, date_literal)
  • Register builtins and collation derivation paths in expression function registry.
  • Align masking builtin semantics with issue-bundle implementation (including binary/UTF8 handling and type-specific behavior).
  • Add/update unit tests for builtin masking behavior.
  • Add/update integration cases in tests/integrationtest/t/expression/builtin.test and expected results.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No need to test
    • I checked and no code files have been changed.

Test commands:

  • GOTOOLCHAIN=go1.25.9 ./tools/check/failpoint-go-test.sh pkg/expression -run 'TestMask(Full|Null|Partial|Date)$'
  • cd tests/integrationtest && ./run-tests.sh -r expression/builtin

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.

Add column masking built-in functions and align their behavior with masking policy design implementation.

Summary by CodeRabbit

  • New Features

    • Added four masking functions: mask_full, mask_null, mask_partial, mask_date (supporting strings, binary, dates/datetimes, time, numeric).
  • Behavior

    • UTF‑8 vs byte semantics respected; partial masking preserves configured left/right portions; mask_date normalizes to target date; invalid parameters return explicit errors.
  • Tests

    • Expanded unit and integration coverage and updated built-in listings and expected outputs.

Review Change Stack

@ti-chi-bot ti-chi-bot Bot added the release-note Denotes a PR that will be considered when it comes time to generate release notes. label May 12, 2026
@pantheon-ai

pantheon-ai Bot commented May 12, 2026 •

Copy link
Copy Markdown

@tiancaiamao I've received your pull request and will start the review. I'll conduct a thorough review covering code quality, potential issues, and implementation details.

⏳ This process typically takes 10-30 minutes depending on the complexity of the changes.

ℹ️ Learn more details on Pantheon AI.

@ti-chi-bot ti-chi-bot Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label May 12, 2026
@tiprow

tiprow Bot commented May 12, 2026

Copy link
Copy Markdown

Hi @tiancaiamao. Thanks for your PR.

PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test all.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@coderabbitai

coderabbitai Bot commented May 12, 2026 •

Copy link
Copy Markdown

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

Adds four masking builtins—mask_full, mask_null, mask_partial, mask_date—with implementations, signature selection, collation derivation updates, unit and integration tests, build/registry wiring, and generated thread-safety wrappers.

Changes

Masking Builtins Feature

Layer / File(s) Summary
Build configuration and function registry
pkg/expression/BUILD.bazel, pkg/expression/builtin.go
Adds builtin_masking.go and builtin_masking_test.go to Bazel targets and registers mask builtins in the funcs registry.
Masking functions core implementation
pkg/expression/builtin_masking.go
Implements mask_full, mask_null, mask_partial, and mask_date with type-specific signature selection and eval logic, including parse helper for YYYY-MM-DD.
Thread-safety wrapper methods (generated)
pkg/expression/builtin_threadsafe_generated.go
Adds SafeToShareAcrossSession() methods for the new builtin mask signature types.
Collation derivation for masking functions
pkg/expression/collation.go
Updates deriveCollation to derive collation from args[0] (and args[3] for partial) for masking builtins.
Unit test coverage
pkg/expression/builtin_masking_test.go
Adds tests for MASK_FULL, MASK_NULL, MASK_PARTIAL, and MASK_DATE, covering valid outputs and argument error cases across string, numeric, and temporal types.
Integration expected results
tests/integrationtest/r/expression/builtin.result
Adds expected outputs for masking functions across string, temporal, blob/clob types, and invalid-argument error cases.
Integration test SQL
tests/integrationtest/t/expression/builtin.test
Adds SQL assertions exercising masking functions and error-case expectations.
Show output & snapshot update
tests/integrationtest/r/executor/show.result, pkg/planner/util/null_misc_test.go, pkg/expression/function_traits_test.go
Extends show builtins expected output, updates the builtin registry snapshot hash, and adds masking functions to the generated-columns whitelist.

Sequence Diagram(s)

sequenceDiagram
  participant SQL as Client
  participant Eval as expression.Evaluator
  participant Factory as mask_* FunctionClass
  participant Sig as mask_* signature
  SQL->>Eval: call mask_full/mask_null/mask_partial/mask_date(args)
  Eval->>Factory: getFunction(arg types/count)
  Factory->>Sig: select signature variant (string/binary/time/num)
  Sig->>Eval: eval -> masked value / NULL / parsed date
  Eval->>SQL: return result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

ok-to-test

Suggested reviewers

  • xzhangxian1008
  • hawkingrei
  • yudongusa
  • qw4990
  • windtalker

Poem

🐰 I hop through code with careful whisk,
Four masks sewn neat, none amiss,
Nulls that vanish, middles now sealed,
Dates aligned where nights are peeled,
Tests applaud my tiny paws.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.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 'expression: add column masking related builtins functions' clearly and accurately summarizes the main change: adding masking-related builtin functions to the expression package.
Description check ✅ Passed The PR description is complete and follows the required template with all critical sections properly filled: issue number, problem summary, detailed explanation of changes, test coverage confirmation, and release notes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

@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: 3

🧹 Nitpick comments (1)
tests/integrationtest/t/expression/builtin.test (1)

1676-1692: ⚡ Quick win

Consider adding test coverage for optional mask_char parameter.

The test coverage for the masking functions is comprehensive, but line 1677 tests mask_full() only with an explicit mask character. Since the PR description indicates mask_char is optional (MASK_FULL(col[, mask_char])), consider adding a test case that exercises the default behavior:

select mask_full('abc'), mask_full(cast('2012-01-02' as date));

This would verify that the default mask character works correctly across different types.

Important: Use the correct recording command for integration tests.

As per coding guidelines, when recording the expected results for these new test cases, you must use the recording command documented in docs/agents/testing-flow.md → Integration tests (not -record).

🤖 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 `@tests/integrationtest/t/expression/builtin.test` around lines 1676 - 1692,
Add a test case that calls mask_full without the optional mask_char to verify
default behavior (e.g., select mask_full('abc'), mask_full(cast('2012-01-02' as
date))) and add similar assertions for other types already exercised; ensure you
record the expected results using the documented integration test recording
command from the testing-flow.md (not the -record flag).
🤖 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 `@pkg/expression/builtin_masking_test.go`:
- Around line 107-136: Extend TestMaskPartial to include a case that uses very
large preserve values (e.g., math.MaxInt64 and math.MaxInt64-1) when
constructing the function via newFunctionForTest with ast.MaskPartial and
primitiveValsToConstants; call f.Eval(ctx, chunk.Row{}) inside require.NotPanics
(and then require.NoError if you expect a normal return) to assert the call does
not panic for extreme preserve_left/preserve_right inputs, referencing
TestMaskPartial, newFunctionForTest, ast.MaskPartial, primitiveValsToConstants,
and chunk.Row{} to locate where to add the case.

In `@pkg/expression/builtin_masking.go`:
- Around line 438-451: The preserve-range check in both
builtinMaskPartialSig.evalString and builtinMaskPartialUTF8Sig.evalString can
overflow when adding preserveLeft and preserveRight (int64) and then panic
during slicing; update both functions to perform overflow-safe checks before
summing (e.g., validate each preserve value against total and use a
subtraction-based comparison like preserveLeft >= total || preserveRight >=
total || preserveLeft > total - preserveRight) so the guard correctly returns
the original string when the preserved ranges cover or exceed total and prevents
computing maskLen or slicing on overflowed values.
- Around line 217-222: The return type for mask_null must never carry the
NotNullFlag; update the mask_null builtin to clone the input field type and
explicitly clear the NotNullFlag before assigning it to bf.tp (i.e., after bf.tp
= argType.Clone(), clear the NotNullFlag on bf.tp). Reference the mask_null
implementation and the bf.tp assignment in builtin_masking.go to locate where to
perform the flag removal.

---

Nitpick comments:
In `@tests/integrationtest/t/expression/builtin.test`:
- Around line 1676-1692: Add a test case that calls mask_full without the
optional mask_char to verify default behavior (e.g., select mask_full('abc'),
mask_full(cast('2012-01-02' as date))) and add similar assertions for other
types already exercised; ensure you record the expected results using the
documented integration test recording command from the testing-flow.md (not the
-record flag).
🪄 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

Run ID: fb23ecfa-d456-47b4-93c4-293097625e14

📥 Commits

Reviewing files that changed from the base of the PR and between fd471d3 and bbcd114.

📒 Files selected for processing (7)
  • pkg/expression/BUILD.bazel
  • pkg/expression/builtin.go
  • pkg/expression/builtin_masking.go
  • pkg/expression/builtin_masking_test.go
  • pkg/expression/collation.go
  • tests/integrationtest/r/expression/builtin.result
  • tests/integrationtest/t/expression/builtin.test

Comment thread pkg/expression/builtin_masking_test.go
Comment thread pkg/expression/builtin_masking.go
Comment thread pkg/expression/builtin_masking.go
@tiancaiamao

Copy link
Copy Markdown
Contributor Author

/retest-required

@tiprow

tiprow Bot commented May 12, 2026

Copy link
Copy Markdown

@tiancaiamao: PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test.

Details

In response to this:

/retest-required

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@tiancaiamao

Copy link
Copy Markdown
Contributor Author

/retest

@tiprow

tiprow Bot commented May 12, 2026

Copy link
Copy Markdown

@tiancaiamao: PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test.

Details

In response to this:

/retest

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@ti-chi-bot ti-chi-bot Bot added the sig/planner SIG: Planner label May 12, 2026
@codecov

codecov Bot commented May 13, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 37.85047% with 266 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.9489%. Comparing base (9bbc86e) to head (b13fd15).
⚠️ Report is 590 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #68321        +/-   ##
================================================
- Coverage   77.3057%   73.9489%   -3.3568%     
================================================
  Files          2010       2044        +34     
  Lines        555533     602621     +47088     
================================================
+ Hits         429459     445632     +16173     
- Misses       125154     154421     +29267     
- Partials        920       2568      +1648     
Flag Coverage Δ
integration 41.1239% <37.8504%> (+1.3298%) ⬆️

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

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

…master

# Conflicts:
#	pkg/expression/function_traits_test.go
#	pkg/planner/util/null_misc_test.go
#	tests/integrationtest/r/executor/show.result
@tiancaiamao tiancaiamao changed the title expression: add column masking builtins aligned with issue bundle expression: add column masking builtins functions May 14, 2026
@tiancaiamao tiancaiamao changed the title expression: add column masking builtins functions expression: add column masking related builtins functions May 14, 2026
%Y-%m-%d %Y-%m-%d %H:%i:%s %Y-%m-%d %H.%i.%s %H%i%s
select mask_full('abc', '*'), mask_full(cast('2012-01-02' as date), '*'), mask_full(cast('2012-01-02 03:04:05' as datetime), '*'), mask_full(cast('03:04:05' as time), '*'), mask_full(cast('2012' as year), '*');
mask_full('abc', '*') mask_full(cast('2012-01-02' as date), '*') mask_full(cast('2012-01-02 03:04:05' as datetime), '*') mask_full(cast('03:04:05' as time), '*') mask_full(cast('2012' as year), '*')
*** 1970-01-01 1970-01-01 00:00:00 00:00:00 0000

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

mask_full(cast('2012-01-02' as date), '*') -> 1970-01-01

Is this expected? if yes, it's better to documented it in the user doc('*' will be ignored).

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.

Fixed ... according to design, mask_full only accept one parameter.

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.

mask_full should only take a single argument (the value to mask), not an
optional second mask character argument. Remove the second argument handling
from getFunction, evalString methods, unit tests, and integration tests.

Addresses PR review comment: mask_full function signature should match the
design spec at docs/design/2026-02-27-column-level-masking.md.
}
return &builtinMaskFullIntSig{bf}, nil
default:
return nil, errIncorrectArgs.GenWithStackByArgs("mask_full")

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.

Do you plan to support DECIMAL and DOUBLE type here?

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.

Updated, now DECIMAL and DOUBLE are supported.

@tiancaiamao

Copy link
Copy Markdown
Contributor Author

/retest

@tiprow

tiprow Bot commented Jun 16, 2026

Copy link
Copy Markdown

@tiancaiamao: PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test.

Details

In response to this:

/retest

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@tiancaiamao
tiancaiamao requested a review from expxiaoli June 16, 2026 01:28

@expxiaoli expxiaoli 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.

LGTM

@ti-chi-bot

ti-chi-bot Bot commented Jun 16, 2026

Copy link
Copy Markdown

@expxiaoli: adding LGTM is restricted to approvers and reviewers in OWNERS files.

Details

In response to this:

LGTM

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

select mask_full('abc', '*'), mask_full(cast('2012-01-02' as date), '*'), mask_full(cast('2012-01-02 03:04:05' as datetime), '*'), mask_full(cast('03:04:05' as time), '*'), mask_full(cast('2012' as year), '*');
mask_full('abc', '*') mask_full(cast('2012-01-02' as date), '*') mask_full(cast('2012-01-02 03:04:05' as datetime), '*') mask_full(cast('03:04:05' as time), '*') mask_full(cast('2012' as year), '*')
*** 1970-01-01 1970-01-01 00:00:00 00:00:00 0000
select mask_full('abc'), mask_full(cast('2012-01-02' as date)), mask_full(cast('2012-01-02 03:04:05' as datetime)), mask_full(cast('03:04:05' as time)), mask_full(cast('2012' as year));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we have plan to support format like mask_partial(birth_date, 'Y-01-01')? There was something like it in the specification doc.

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.

You mean mask_date, not mask_partial...
I've updated the code to support that.

return nil, err
}
argType := args[0].GetType(ctx.GetEvalCtx())
bf.tp = argType.Clone()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What if args[0] is of non-string types?

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.

check added

@tiancaiamao
tiancaiamao requested a review from bb7133 June 18, 2026 03:38
@tiancaiamao

Copy link
Copy Markdown
Contributor Author

PTAL @bb7133

@expxiaoli expxiaoli 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.

LGTM

@ti-chi-bot

ti-chi-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: expxiaoli
Once this PR has been reviewed and has the lgtm label, please assign gengliqi, hawkingrei for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found 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 the needs-1-more-lgtm Indicates a PR needs 1 more LGTM. label Aug 17, 2026
@ti-chi-bot

ti-chi-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown

[LGTM Timeline notifier]

Timeline:

  • 2026-08-17 06:17:43.918433892 +0000 UTC m=+3632049.954528948: ☑️ agreed by expxiaoli.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-1-more-lgtm Indicates a PR needs 1 more LGTM. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/planner SIG: Planner 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.

column masking policy: MASK_FULL has incorrect signature - should not require mask_char parameter

3 participants