column masking policy: MASK_PARTIAL has incorrect type signature allowing wrong parameter order
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 75/100
Research direction
Start in pkg/expression/builtin_masking.go at maskPartialFunctionClass.getFunction, then review the related cases in pkg/expression/builtin_masking_test.go and the signature documented in docs/design/2026-02-27-column-level-masking.md. Run the focused expression tests first. Done means incorrect MASK_PARTIAL argument orders fail type checking, the documented order succeeds, and masking behavior remains correct.
Written by the indexing model from the issue text.
Description
Bug Report
The MASK_PARTIAL function has an incorrect type signature in its implementation, which allows invalid parameter orders to pass type checking.
Error/Incorrect Behavior
When creating a masking policy with incorrect parameter order:
```sql
-- This INCORRECT syntax currently succeeds (should fail)
CREATE MASKING POLICY p_test ON t(credit_card)
AS MASK_PARTIAL(credit_card, '*', 4, 4);
```
Expected behavior: Should fail with a type error
Actual behavior: Succeeds (but may produce incorrect results at runtime)
The correct syntax should be:
```sql
CREATE MASKING POLICY p_test ON t(credit_card)
AS MASK_PARTIAL(credit_card, 4, 4, '*');
```
Root Cause
In pkg/expression/builtin_masking.go, the maskPartialFunctionClass.getFunction has an incorrect type signature:
```go
// Line 337 - INCORRECT (has extra ETString)
bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args,
types.ETString, // args[0]: str
types.ETString, // <-- EXTRA TYPE SIGNATURE (should not exist)
types.ETInt, // args[1]: preserveLeft
types.ETInt, // args[2]: preserveRight
types.ETString) // args[3]: pad
```
The function signature should be:
```go
bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args,
types.ETString, // args[0]: str
types.ETInt, // args[1]: preserveLeft
types.ETInt, // args[2]: preserveRight
types.ETString) // args[3]: pad
```
Impact
- Silent errors: Users can create masking policies with wrong parameter orders that only fail at runtime
- Incorrect masking: The function may produce unexpected results instead of properly masking data
- Poor UX: Error messages don't catch the issue at policy creation time
Verification
Current Behavior (Bug)
```sql
CREATE TABLE t(credit_card VARCHAR(20));
CREATE MASKING POLICY p_test ON t(credit_card)
AS MASK_PARTIAL(credit_card, '*', 4, 4);
-- Succeeds (SHOULD FAIL)
```
Expected Behavior (Fix)
```sql
CREATE TABLE t(credit_card VARCHAR(20));
CREATE MASKING POLICY p_test ON t(credit_card)
AS MASK_PARTIAL(credit_card, '*', 4, 4);
-- Should fail with type error: argument 2 should be int, got string
```
```sql
CREATE TABLE t(credit_card VARCHAR(20));
CREATE MASKING POLICY p_test ON t(credit_card)
AS MASK_PARTIAL(credit_card, 4, 4, '*');
-- Should succeed (correct parameter order)
```
Design Documentation
According to `docs/design/2026-02-27-column-level-masking.md`:
- `MASK_PARTIAL(col, preserve_left, preserve_right, mask_char)` - Partially masks string values while preserving both ends
- `preserve_left`: Number of leading characters to keep
- `preserve_right`: Number of trailing characters to keep
- `mask_char`: Single character used for masking
- Example: `MASK_PARTIAL(credit_card, 6, 4, '*')` keeps first 6 and last 4 characters
Fix Required
In `pkg/expression/builtin_masking.go`, line 337:
Current (incorrect):
```go
bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString, types.ETInt, types.ETInt, types.ETString)
```
Should be:
```go
bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETInt, types.ETInt, types.ETString)
```
Remove the extra `types.ETString` in the type signature.
Test Cases Needed
- Test that `MASK_PARTIAL(col, 'char', 1, 1)` fails with type error
- Test that `MASK_PARTIAL(col, 1, 1, 'char')` succeeds
- Test that `MASK_PARTIAL(col, 'char', 'char', 1)` fails with type error
- Verify actual masking behavior works correctly with proper parameters
Component
- `component/expression`
- `component/ddl`
Related Files
- Implementation: `pkg/expression/builtin_masking.go` (line 337)
- Test: `pkg/expression/builtin_masking_test.go`
- Design: `docs/design/2026-02-27-column-level-masking.md`
Related Issues
- #67217: Policy name uniqueness test coverage
- #67218: CTE test coverage
- #67219: CREATE OR REPLACE test coverage
- #67221: Dynamic privileges not implemented
- Dominant language
- Go
- Stars
- 40.6k
- Forks
- 6.2k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 168
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from pingcap/tidb
-
affects-9.0 found-by-ai may-affects-25.10 may-affects-26.3 may-affects-26.9 may-affects-7.5 may-affects-8.1 may-affects-8.5 severity/major sig/execution type/bug
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
-
affects-8.1 affects-8.5 component/statistics severity/moderate type/bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
affects-26.3 affects-9.0 component/ddl found-by-ai severity/major type/bug
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
-
contribution may-affects-25.10 may-affects-26.3 may-affects-26.9 may-affects-7.5 may-affects-8.1 may-affects-8.5 severity/major sig/execution type/bug
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
-
component/test severity/minor type/bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 84/100
-
enhancement needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
kind/cleanup
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
kubernetes-sigs/kueue#15947 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
sympozium-ai/sympozium#627 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100