MySQL 9.7.0
Source Code Documentation
sql_masking_policy.cc File Reference
#include "sql/sql_masking_policy.h"
#include <algorithm>
#include <cassert>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <utility>
#include "field_types.h"
#include "lex_string.h"
#include "map_helpers.h"
#include "my_alloc.h"
#include "my_inttypes.h"
#include "my_sys.h"
#include "mysql/components/my_service.h"
#include "mysql/components/service.h"
#include "mysql/components/services/mysql_string.h"
#include "mysql/components/services/object_policy_service.h"
#include "mysql/psi/mysql_mutex.h"
#include "mysql/strings/m_ctype.h"
#include "mysql/udf_registration_types.h"
#include "mysql_com.h"
#include "mysqld_error.h"
#include "scope_guard.h"
#include "sql/auth/sql_security_ctx.h"
#include "sql/create_field.h"
#include "sql/derror.h"
#include "sql/enum_query_type.h"
#include "sql/field.h"
#include "sql/field_common_properties.h"
#include "sql/item.h"
#include "sql/item_cmpfunc.h"
#include "sql/item_func.h"
#include "sql/mem_root_array.h"
#include "sql/mysqld.h"
#include "sql/mysqld_cs.h"
#include "sql/sp.h"
#include "sql/sql_base.h"
#include "sql/sql_class.h"
#include "sql/sql_const.h"
#include "sql/sql_error.h"
#include "sql/sql_lex.h"
#include "sql/sql_parse.h"
#include "sql/table.h"
#include "sql_string.h"
#include "string_with_len.h"
#include "template_utils.h"

Functions

static LEX_CSTRING make_lex_cstring (MEM_ROOT *root, const String &string)
 
static bool equal_names_for_masking_policy (std::string_view name1, std::string_view name2)
 Returns true if the two names are considered equal when they are used either as masking policy names or as masking policy argument names. More...
 
static bool invalidate_tables_with_masking_policy (THD *thd, std::string_view policy_name)
 Iterate the Table Definition Cache (TDC) to find tables whose TABLE_SHARE has at least one field referencing the given masking policy name and invalidate those tables so they will be reopened with up-to-date metadata. More...
 
bool drop_masking_policy (THD *thd, LEX_CSTRING policy_name, bool if_exists)
 Drop the masking policy with the given name. More...
 
std::optional< Sql_masking_policy_specget_masking_policy_spec (THD *thd, LEX_CSTRING policy_name, std::string *reason)
 Returns the masking policy with the given name if it can be found. More...
 
bool check_masking_policy_manage_privilege (THD *thd)
 Checks if the current user has the MANAGE_DATA_MASKING_POLICY privilege. More...
 
bool create_masking_policy (THD *thd, bool if_not_exists, const Sql_masking_policy_spec &spec)
 Create a masking policy with the given specification. More...
 
static bool validate_masking_policy_column_constraints (const Create_field &create_field)
 Validates constraints for masking policy assignment on a column. More...
 
bool check_masking_policy_name (LEX_CSTRING name)
 Check if the name is valid for a masking policy name or a masking policy argument name. More...
 
static bool validate_masking_policy_gatekeeper (Item *gatekeeper_expr)
 
static bool validate_policy_argument_reference (Item_field *field, LEX_CSTRING argument_name)
 The only column references allowed in a masking function are unqualified names (no schema or table) that are equal to the policy's argument name. More...
 
static bool validate_masking_function_syntax (THD *thd, Item *masking_func, LEX_CSTRING argument_name)
 Perform pre-resolving checks for the validity of the masking function: More...
 
bool validate_masking_policy_syntax (THD *thd, LEX_CSTRING argument_name, Item *expr)
 Validate structural and semantic restrictions for a masking policy expression. More...
 
static bool compatible_string_types (const Item_field *col, const Item *expr)
 Check if both items have compatible (simple-string) types and collation. More...
 
static bool is_simple_integer_or_year_type (enum_field_types type)
 Returns true if type is a plain integer or YEAR. More...
 
static bool compatible_int_types (const Item_field *col, const Item *expr)
 Returns true if the types of the two items are identical, or if both are "simple" integers (including YEAR). More...
 
static bool compatible_temporal_types (const Item_field *col, const Item *expr)
 Returns true if both items have the same temporal type (DATETIME and TIMESTAMP are considered the same type) with the same fractional seconds precision (FSP). More...
 
static bool compatible_types (const Item_field *col, const Item *expr)
 Checks whether the column and resolved masking expression are type-compatible for masking. More...
 
static bool validate_masking_policy_for_column (Item_field *item_field, Item *mask_expr)
 Validates that the resolved masking expression is appropriate for the specified column: checks type compatibility and that the expression is deterministic. More...
 
static Itemwrap_gatekeeper_in_item_cache (Item *mask_expr)
 
Itemresolve_masking_expression (THD *thd, Item_field *item_field, const Sql_masking_policy_spec &spec)
 Parse and resolve the column’s masking expression under the column’s security context. More...
 
bool validate_masking_policy_for_create_alter_table (THD *thd, uchar *buf, TABLE *table, const Create_field &field)
 Validates masking policies for CREATE/ALTER TABLE. More...
 

Variables

constexpr char kComponentUnavailable [] = "component is unavailable"
 
constexpr char kStringConversionFailed [] = "string conversion failed"
 
constexpr char kNoMessage [] = "(no message)"
 

Function Documentation

◆ check_masking_policy_manage_privilege()

bool check_masking_policy_manage_privilege ( THD thd)

Checks if the current user has the MANAGE_DATA_MASKING_POLICY privilege.

Raises an error if the privilege is missing.

Parameters
thdThread context
Return values
falsePrivilege is granted
truePrivilege is missing (error is reported)

◆ check_masking_policy_name()

bool check_masking_policy_name ( LEX_CSTRING  name)

Check if the name is valid for a masking policy name or a masking policy argument name.

Raises an error if it is not valid.

Parameters
nameName to validate
Return values
falseName is valid
trueValidation failed (error is reported)

◆ compatible_int_types()

static bool compatible_int_types ( const Item_field col,
const Item expr 
)
static

Returns true if the types of the two items are identical, or if both are "simple" integers (including YEAR).

"Simple" excludes types with special semantics such as BIT.

◆ compatible_string_types()

static bool compatible_string_types ( const Item_field col,
const Item expr 
)
static

Check if both items have compatible (simple-string) types and collation.

Returns true if compatible, false otherwise.

◆ compatible_temporal_types()

static bool compatible_temporal_types ( const Item_field col,
const Item expr 
)
static

Returns true if both items have the same temporal type (DATETIME and TIMESTAMP are considered the same type) with the same fractional seconds precision (FSP).

◆ compatible_types()

static bool compatible_types ( const Item_field col,
const Item expr 
)
static

Checks whether the column and resolved masking expression are type-compatible for masking.

Assumes both Items are resolved. Policy:

  • Result kinds (Item_result) must match.
  • REAL_RESULT: identical precision; data_type() must match (both FLOAT or both DOUBLE).
  • INT_RESULT: identical types or both simple integers (including YEAR).
  • DECIMAL_RESULT: identical scale (decimals). Precision may differ.
  • STRING_RESULT: handled as either:
    • temporal types: same temporal family (DATE, TIME, DATETIME/TIMESTAMP) and identical FSP (Item::decimals),
    • simple string types: identical collation; types may differ if both are simple string types (CHAR/VARCHAR/BLOB/TEXT variants), or
    • other string-result types: require identical data_type() to avoid semantic shifts (e.g., JSON/geometry). This guarantees identical comparison and ordering semantics. Other result kinds are not expected here. Returns true if compatible.

◆ create_masking_policy()

bool create_masking_policy ( THD thd,
bool  if_not_exists,
const Sql_masking_policy_spec spec 
)

Create a masking policy with the given specification.

Parameters
thdThread context
if_not_existsTrue if CREATE MASKING POLICY IF NOT EXIST, which means it is not an error if the policy already exists. The existing policy is kept.
specMasking policy specification
Return values
falseOn success
trueIf an error has been raised

◆ drop_masking_policy()

bool drop_masking_policy ( THD thd,
LEX_CSTRING  policy_name,
bool  if_exists 
)

Drop the masking policy with the given name.

Parameters
thdThread context
policy_nameThe name of the policy to drop
if_existsTrue if DROP IF EXISTS, which means it is not an error to call it with a policy name that does not exist.
Return values
trueIf an error is raised
falseOn success

◆ equal_names_for_masking_policy()

static bool equal_names_for_masking_policy ( std::string_view  name1,
std::string_view  name2 
)
static

Returns true if the two names are considered equal when they are used either as masking policy names or as masking policy argument names.

◆ get_masking_policy_spec()

std::optional< Sql_masking_policy_spec > get_masking_policy_spec ( THD thd,
LEX_CSTRING  policy_name,
std::string *  reason 
)

Returns the masking policy with the given name if it can be found.

Returns an empty result if the masking policy with that name could not be found. No error is raised, but the output parameter reason contains the reason why the masking policy was not found.

Parameters
thdThread context
policy_nameThe name of the policy to look for
[out]reasonIf the function returns an empty value, this parameter will return the reason why the policy was not found.
Returns
The policy specification if found; otherwise empty.

◆ invalidate_tables_with_masking_policy()

static bool invalidate_tables_with_masking_policy ( THD thd,
std::string_view  policy_name 
)
static

Iterate the Table Definition Cache (TDC) to find tables whose TABLE_SHARE has at least one field referencing the given masking policy name and invalidate those tables so they will be reopened with up-to-date metadata.

Locking and safety:

  • Acquire LOCK_open while scanning table_def_cache and reading TABLE_SHARE members; skip shares with m_open_in_progress.
  • Copy db/table names to thd->mem_root while holding LOCK_open; perform invalidation after unlocking to avoid lock ordering issues.
  • Use tdc_remove_table(..., TDC_RT_MARK_FOR_REOPEN_AND_INVALIDATE_SHARE, has_lock=false) to mark open TABLEs for reopen and invalidate the share.

◆ is_simple_integer_or_year_type()

static bool is_simple_integer_or_year_type ( enum_field_types  type)
static

Returns true if type is a plain integer or YEAR.

◆ make_lex_cstring()

static LEX_CSTRING make_lex_cstring ( MEM_ROOT root,
const String string 
)
static

◆ resolve_masking_expression()

Item * resolve_masking_expression ( THD thd,
Item_field item_field,
const Sql_masking_policy_spec spec 
)

Parse and resolve the column’s masking expression under the column’s security context.

Replaces the policy argument with the actual Item_field and keeps name resolution otherwise empty to prevent references to other columns.

Parameters
thdThread context
item_fieldColumn reference substituted for the policy argument
specMasking policy specification (previously fetched)
Returns
a pointer to the resolved Item on success, or nullptr on error (error is reported)

◆ validate_masking_function_syntax()

static bool validate_masking_function_syntax ( THD thd,
Item masking_func,
LEX_CSTRING  argument_name 
)
static

Perform pre-resolving checks for the validity of the masking function:

  • Must not reference other columns than the argument to the masking policy.
  • Must return exactly one value.
  • Must not use functions that are not allowed in a generated column (exception: UDFs are allowed).

Perform the generated column pre-resolving check, with exception for UDFs.

◆ validate_masking_policy_column_constraints()

static bool validate_masking_policy_column_constraints ( const Create_field create_field)
static

Validates constraints for masking policy assignment on a column.

Central checker for column-level eligibility: enforces the constraints listed under "Checked here" and enumerates related constraints validated elsewhere (with pointers), so this block is the canonical index of eligibility rules.

Constraints checked here:

  • The column must not be a generated column.
  • For existing columns (create_field.field != nullptr), the column must not have a histogram.

Constraints validated elsewhere:

  • The column must not be indexed. Checked in prepare_key_column().
  • The column must not be referenced by generated columns, functional indexes, DEFAULT value expressions or CHECK constraints. Checked by Item_field::check_function_as_value_generator().
  • The column must not be used by the table partitioning/subpartitioning function. This is enforced during partition function fixing in sql_partition.cc (fix_partition_func/create_partition_field_array), which raises ER_MASKING_POLICY_INCOMPATIBLE_COLUMN_FEATURE when a partition key references a masked column.
Parameters
create_fieldCreate_field object for the column to validate
Return values
trueValidation failed, error was reported
falseValidation succeeded

◆ validate_masking_policy_for_column()

static bool validate_masking_policy_for_column ( Item_field item_field,
Item mask_expr 
)
static

Validates that the resolved masking expression is appropriate for the specified column: checks type compatibility and that the expression is deterministic.

Reports errors for incompatible/unsafe masking policies. Rationale: users permitted to see the unmasked value must observe behavior identical to a column without a policy: both presentation and semantics must match. In particular, comparison and ordering must not change (same collation/charset), and numeric precision/scale must be preserved; the expression must be deterministic. Assumes: mask_expr is fully resolved (types, collation/charset, nullability).

◆ validate_masking_policy_for_create_alter_table()

bool validate_masking_policy_for_create_alter_table ( THD thd,
uchar buf,
TABLE table,
const Create_field field 
)

Validates masking policies for CREATE/ALTER TABLE.

Performs validation in three categories and delegates details to helpers:

  • Column eligibility for masking (validate_masking_policy_column_constraints()).
  • Masking function resolution and post-resolve validation (validate_masking_function_post_resolve()).
  • Column/function type compatibility (compatible_types()).

See the referenced helpers for detailed rules and rationale.

Parameters
thdThread context
bufRow buffer used to back a temporary Field instance
tableTable being created/altered
fieldColumn definition being validated
Return values
trueValidation failed (error was reported)
falseValidation succeeded

◆ validate_masking_policy_gatekeeper()

static bool validate_masking_policy_gatekeeper ( Item gatekeeper_expr)
static

◆ validate_masking_policy_syntax()

bool validate_masking_policy_syntax ( THD thd,
LEX_CSTRING  argument_name,
Item expr 
)

Validate structural and semantic restrictions for a masking policy expression.

Rules enforced:

  • Must use the form CASE WHEN <CURRENT_USER_IN|CURRENT_ROLE_IN>(...) THEN <expr> ELSE <expr>
  • Exactly one WHEN clause and a required ELSE clause
  • THEN/ELSE must meet generated-column-like rules (UDFs allowed)
  • Only the policy argument may reference a column
  • Either THEN or ELSE must return the unmasked value
Parameters
thdThread context
argument_nameName of the argument used in the policy
exprExpression tree of the policy
Return values
trueValidation failed (error reported)
falseValidation succeeded

◆ validate_policy_argument_reference()

static bool validate_policy_argument_reference ( Item_field field,
LEX_CSTRING  argument_name 
)
static

The only column references allowed in a masking function are unqualified names (no schema or table) that are equal to the policy's argument name.

◆ wrap_gatekeeper_in_item_cache()

static Item * wrap_gatekeeper_in_item_cache ( Item mask_expr)
static

Variable Documentation

◆ kComponentUnavailable

constexpr char kComponentUnavailable[] = "component is unavailable"
constexpr

◆ kNoMessage

constexpr char kNoMessage[] = "(no message)"
constexpr

◆ kStringConversionFailed

constexpr char kStringConversionFailed[] = "string conversion failed"
constexpr