Domain 2 of 4 · Chapter 2 of 2

Govern Unity Catalog Objects

Make data discoverable with comments

A catalog with hundreds of tables is only useful if people can find the right one, and the cheapest way to make a table findable is to describe it. In Unity Catalog you attach a plain-language description to any securable object with a comment, and that text becomes part of the object's metadata rather than a note in a separate wiki. This page and its sibling Secure Unity Catalog Objects work the same objects through two lenses: Secure owns who may reach and administer an object, and introduces row filters, column masks, and ABAC as the fine-grained access-control layers stacked on the object grant (peers rather than rungs on a single scale of fineness), while this page owns describing, recording, retaining, and sharing it, and goes deep on configuring and choosing among those same three controls. So when filters, masks, and ABAC return below, that is the deep pass rather than a repeat.

Set a table's description with the COMMENT ON[1] command or the COMMENT clause of CREATE/ALTER TABLE; set a column's description with ALTER TABLE ... ALTER COLUMN ... COMMENT, which is the only way to document an individual column (Add comments to data and AI assets[2]). You can also edit any comment in Catalog Explorer, where saving one runs an ALTER statement under the covers. A table comment documents what the dataset is; per-column comments document each field.

Because a comment is stored as Unity Catalog metadata, it survives schema changes and shows up wherever the catalog is searched. Any user with the BROWSE privilege can read it, and the text feeds Catalog Explorer search and the natural-language answers in AI/BI Genie (Add comments to data and AI assets[2]). You write the description once and every discovery surface reuses it, so a user understands a table without opening the files behind it.

For a large or legacy catalog, writing every description by hand is the bottleneck. Catalog Explorer can propose AI-generated comments (also called AI-generated documentation) for a table and for each of its columns; a data steward reviews the suggestion and clicks Accept, or edits it first (Add AI-generated comments to Unity Catalog objects[3]). The review step is the point: the model proposes and a human approves, so a big catalog gets documented quickly without publishing text nobody checked.

Describe a table and one of its columns

This adds a dataset-level description and a column description; the rest of the schema is unchanged:

COMMENT ON TABLE sales.orders IS 'One row per confirmed customer order';
ALTER TABLE sales.orders ALTER COLUMN email COMMENT 'Customer contact email';
-- ...

COMMENT ON TABLE sets the table description, and the ALTER COLUMN ... COMMENT form is what documents the email column specifically.

Row filters and column masks

Two Unity Catalog controls limit what a principal sees inside a table at query time, and the exam turns on telling them apart: a row filter removes whole rows, and a column mask rewrites individual values. The figure below shows both on one query path: the row filter drops whole rows, then the column mask redacts values in the rows that remain. Both are SQL user-defined functions (UDFs) that Unity Catalog evaluates on every query, and both attach to the table itself, so a query through any SQL warehouse, notebook, or client sees the same enforcement (Row filters and column masks[4]).

A row filter is a boolean SQL UDF bound to a table with ALTER TABLE <table> SET ROW FILTER. Unity Catalog runs the function once per row and keeps the row only when it returns TRUE; a row where the function returns FALSE is excluded from the result (Row filters and column masks[4]). Use it for row-level security, such as limiting each analyst to their own region's records. What a row filter cannot do is show part of a value: it decides whole rows in or out, with nothing in between.

A column mask is a SQL UDF bound to one column with ALTER TABLE <table> ALTER COLUMN <col> SET MASK. It takes the column value and returns either the original or a redacted version, so every row is still returned but the sensitive column is rewritten, for example revealing only the last four digits of a card or only the domain after the @ in an email (Row filters and column masks[4]). Reach for a column mask exactly when a row filter is too blunt, when the row must stay visible but one field must be partly hidden.

That distinction drives a least-privilege point worth internalizing. Masking a sensitive column while leaving table SELECT in place lets the query run and return every row, with only the protected field redacted. Revoking access instead is coarser and breaks any query that references the column, so a masked column follows least privilege where a revoke does not.

One hard boundary decides many questions: row filters and column masks attach to base tables (and, through ABAC policies — attribute-based access control rules introduced in the next section — to materialized views and streaming tables), but you cannot place them on a standard view (Row filters and column masks, Limitations[4]). If a stem puts SET MASK on a CREATE VIEW, it is wrong; to filter or mask through a view, use a dynamic view[5] whose logic lives in the view definition.

The order of enforcement is easiest to see as a pipeline: the base table's rows enter, the row filter drops the ones its UDF rejects, the column mask rewrites the protected values in the rows that remain, and the caller receives a filtered, redacted result.

Base tableall rows, real valuesRow filterdrops whole rowsColumn maskredacts valuesQuery resultfewer rows, masked cells
Query-time enforcement: a row filter drops whole rows, then a column mask redacts values in the rows that remain. Source: Azure Databricks row filters and column masks.

Scale protection with ABAC and governed tags

Configuring SET ROW FILTER or SET MASK on every table stops scaling the moment you have hundreds of them. Attribute-based access control (ABAC) solves that by protecting data based on a tag instead of a table name: you tag the sensitive data once, write one policy, and it covers every table that carries the tag, today and in the future (Attribute-based access control in Unity Catalog[6]).

The vocabulary ABAC evaluates is the governed tag: an account-level tag key with a defined set of allowed values, plus permissions that control who may assign it (Governed tags[7]). Governed tags are enforced across every workspace in the account, so a pii or classification tag means the same thing everywhere. An account can hold up to 1,000 governed tags, each with up to 50 allowed values (Governed tags[7]).

An ABAC policy is the enforcement half. You attach a policy at a catalog, schema, or table, and its condition targets a governed tag; when an object carries the matching tag, the policy applies its row filter or column mask automatically, to every current and future object that matches (Attribute-based access control in Unity Catalog[6]). This is the contrast the exam probes: a table-level SET MASK protects one table and must be repeated on the next, while one ABAC policy on a pii tag governs an entire catalog at once. ABAC also supports materialized views and streaming tables, which the table-level form does not (ABAC vs table-level controls[8]).

Tagging scales because tags flow downhill. A governed tag applied to a catalog or schema is inherited by the objects within it, so tagging a schema propagates the attribute to its tables without touching each one (Governed tags, Inheritance[7]). One exception is easy to misread and worth pinning down: inheritance reaches the tables inside a catalog or schema but not individual table columns, so a column-level classification has to be tagged on the column directly. The figure below draws that hierarchy: the pii tag on the catalog, inherited down through the schema to the customers and payments tables where the ABAC policy applies, and the columns that do not inherit it. Put together, you tag a catalog, attach one policy, and both the tag and its protection reach every descendant table automatically.

Cataloggoverned tag: piiABAC policy at catalogfilter / mask on piiSchemainherits piiTable: customerspolicy appliesTable: paymentspolicy appliesattachedtag inheritedinheritedinheritedColumns do not inherit tags
A governed tag on a catalog inherits to its tables; one ABAC policy then protects every tag-matched object. Source: Azure Databricks governed tags and ABAC.

Trace lineage before you change a table

Governance is not only about restricting access; it is about answering "where did this data come from" and "who touched it." Unity Catalog answers both automatically, so you query the record instead of building one. Lineage answers the first question; the audit log, in the next section, answers the second.

Data lineage is captured automatically for queries and workflows run on Azure Databricks, down to the column level, with no configuration, and it is aggregated across every workspace attached to the metastore (Lineage in Unity Catalog[9]). In Catalog Explorer, the Lineage tab renders an interactive graph of upstream and downstream tables, columns, notebooks, jobs, and dashboards, alongside the object's owner and history. Before you change or drop a column, that graph is the impact analysis: it shows exactly which downstream tables and dashboards depend on it.

So lineage is never documentation somebody has to maintain: it is captured for you, column by column, across every workspace on the metastore, which is what makes it trustworthy enough to decide a change on.

Audit access with system tables and diagnostic settings

Now the second question: who touched it. Audit logs record access rather than structure. Every action against a securable is written to the system.access.audit[10] system table, which captures the principal (user_identity), the securable, and the action taken (action_name, for example getTable), and holds both account-level and workspace-level events. Its free retention period is 365 days (System tables reference[11]), so one query answers "who read this table last month" across the account.

For retention beyond a year, or to route events into an existing monitoring stack, configure Azure diagnostic settings on the workspace. Diagnostic settings stream the same Azure Databricks audit (diagnostic) logs to a Log Analytics workspace, an Azure storage account, or an Azure Event Hubs namespace, which is how you get long-term archival, Azure Monitor querying, and alerting (Configure diagnostic log delivery[12]).

By default the audit log records that an operation happened but not the text of what ran. Enabling verbose audit logging adds fine-grained command events, the notebook and jobs runCommand actions and the Databricks SQL commandSubmit and commandFinish actions, which capture notebook-cell and SQL-warehouse command activity that standard logging omits (Enable verbose audit logs[13]). Turn it on when an audit needs the actual queries, not just the fact that a query ran.

The figure below draws the two destinations for one event: every audit event lands in the queryable system.access.audit table, and, if you configure it, the same event also streams out through diagnostic settings to Log Analytics, a storage account, or Event Hubs. The exam split follows the two destinations: the system table answers anything inside the last 365 days, and diagnostic settings are what you configure when the answer has to reach further back or land in an Azure monitoring stack.

Workspace activityquery, grant, shareAudit eventsystem.access.auditqueryable, 365 daysAzure diagnostic settingsstream outLog AnalyticsStorage accountEvent Hubsrecordedif enabled
Every access becomes an audit event: queryable in system.access.audit (365 days) and optionally streamed via Azure diagnostic settings. Source: Azure Databricks audit log and diagnostic log delivery.

Time travel, retention, and VACUUM

Delta time travel lets you query or restore an earlier version of a table, but it only reaches as far back as two retention windows allow, and running VACUUM can close that window for good. Two table properties set the windows, and confusing them is a classic trap.

delta.logRetentionDuration controls how long the transaction-log history is kept, and it defaults to 30 days (Table properties reference[14]). Because time travel resolves a version or timestamp against that log, this property bounds how far back a time-travel query can reference. delta.deletedFileRetentionDuration controls how long data files that have been logically removed are kept before VACUUM may delete them, and it defaults to 7 days (interval 1 week) (Table properties reference[14]). The two govern different things: one keeps the log (how far back you can name a version), the other keeps the files (whether that version's data still exists on storage).

VACUUM is where recoverability meets cost. It permanently removes data files that are no longer referenced by the latest table version and are older than the retention threshold, which reclaims storage and ensures deleted records are truly gone (Remove unused data files with vacuum[15]). The trade-off is stated plainly in the docs: the ability to query table versions older than the retention period is lost after running VACUUM (Remove unused data files with vacuum[15]). Once the files for a version are purged you can no longer time-travel to it, even if a log entry still names it.

The practical rule follows directly. To preserve the ability to roll back or audit older versions, raise delta.deletedFileRetentionDuration before you run VACUUM, and keep delta.logRetentionDuration at least as long as the history you want to name. To reclaim storage or guarantee a deleted record is unrecoverable, run VACUUM and accept that the older versions go with it.

Lengthen the recoverability window before vacuuming

This raises both retention windows so older versions stay recoverable; the values shown are examples, not the defaults:

ALTER TABLE sales.orders SET TBLPROPERTIES (
  'delta.deletedFileRetentionDuration' = 'interval 30 days',
  'delta.logRetentionDuration'         = 'interval 30 days'
);
-- ...

delta.deletedFileRetentionDuration is the window VACUUM honors before it may purge files, and delta.logRetentionDuration bounds the versions time travel can name.

Share selected data with OpenSharing

When you give another team or company read access to specific tables, the goal is to expose exactly those tables and nothing else. OpenSharing (previously Delta Sharing) does that with a share: a read-only collection that holds only the tables or views you add, granted to a named recipient (What is OpenSharing?[16]). Keep the two labels apart from here on: OpenSharing names the feature, while open sharing in lower case names one of its two recipient modes, the Databricks-to-Open path described below. The recipient sees the objects in the share and never the rest of the metastore, and you can add, remove, or revoke access at any time.

How the recipient authenticates depends on who they are, and this is the distinction the exam tests. If the recipient works in another Unity Catalog-enabled Databricks workspace, use Databricks-to-Databricks sharing: you create a recipient of authentication type DATABRICKS, matched to the recipient's metastore by a sharing identifier (a cloud:region:uuid string) (Create data recipients for OpenSharing[17]). No bearer token is created or managed, and identity verification, authentication, and auditing are handled by the platform over a secure Databricks-managed channel. That is the whole advantage: nothing to rotate.

If the recipient is on any other platform, or has no Unity Catalog-enabled workspace, use open sharing (the Databricks-to-Open protocol) with a recipient of authentication type TOKEN. Azure Databricks generates a long-lived bearer token, a credential file that includes the token, and an activation link that you send over a secure channel; the recipient downloads the credential and uses it to authenticate (Create a recipient using bearer tokens[18]). Because that token grants read access, it must be kept secret and rotated if it is ever exposed. Only this open-sharing path issues a token; Databricks-to-Databricks does not, which is why "eliminate token management" always points to the Databricks-to-Databricks answer.

One governance interaction is worth flagging: a provider cannot share a table that has table-level row filters or column masks applied (What is OpenSharing?, Limitations[16]). To share a redacted slice, expose a dynamic view rather than the protected base table.

Exam-pattern recognition

Most govern-objects questions hand you a goal and a constraint, then ask for the single control that satisfies both. Read the stem for the signal and match it.

  • Hide whole rows by identity (region, department, owner): attach a row filter with ALTER TABLE ... SET ROW FILTER. If the same rule must cover many tables by classification, use an ABAC policy on a governed tag instead.
  • Reveal only part of a value (last four digits, email domain): a column mask with ALTER TABLE ... ALTER COLUMN ... SET MASK. A row filter cannot do partial redaction.
  • Let the query keep running while a sensitive column is hidden: mask the column and keep table SELECT; do not revoke column access, which errors the query.
  • Apply one rule across a whole catalog, including tables added later: a governed tag plus an ABAC policy at the catalog or schema, not per-table configuration.
  • Put a filter or mask on a view: not allowed on a standard view; the controls attach to tables, or you use a dynamic view.
  • Find out who read a table: query system.access.audit (365-day retention). To keep logs longer or to alert, stream them via Azure diagnostic settings to Log Analytics.
  • Capture the actual command text that ran: enable verbose audit logging (runCommand, commandSubmit, commandFinish).
  • Trace what a column feeds before you drop it: the Catalog Explorer Lineage tab, which captures column-level lineage automatically.
  • Keep the ability to roll back older versions: raise delta.deletedFileRetentionDuration before VACUUM; once VACUUM purges the files, time travel to those versions is gone.
  • Share tables with another Databricks org without managing tokens: OpenSharing Databricks-to-Databricks (recipient type DATABRICKS). For a non-Databricks partner, open sharing issues a bearer token you must secure and rotate.

Choosing a Unity Catalog data-protection control

ControlWhat it hidesAttached withScales across tables?Query still runs?
Row filterWhole rows the UDF rejectsALTER TABLE ... SET ROW FILTERNo, one table at a timeYes
Column maskPart of a column valueALTER TABLE ... ALTER COLUMN ... SET MASKNo, one column at a timeYes
ABAC policyRows or columns on tag-matched objectsCREATE POLICY on a catalog or schema by governed tagYes, many tables at onceYes
Revoke SELECTAll access to the table or columnREVOKE SELECTGrant-scopedNo, the query errors

Decision tree

Restrict whole rows by identity?Same rule across many tables?Reveal only part of a value?ABAC policygoverned tag, many tablesRow filterSET ROW FILTERColumn maskSET MASKRevoke SELECTbreaks queriesYesNoYesNoYesNo

Sharp facts the exam loves — give these one last read before exam day.

Cheat sheet

Sharp facts the exam loves — scan these before test day.

Table and column descriptions are added with the COMMENT clause

Descriptions for discovery are set with the COMMENT clause or COMMENT ON and can be edited in Catalog Explorer; a table comment documents the dataset and per-column comments document each field, all stored as Unity Catalog metadata.

10 questions test this
AI-generated comments propose table and column descriptions for review

Catalog Explorer can suggest AI-generated table and column descriptions that a data steward reviews and accepts, accelerating the documentation of large catalogs so that objects become discoverable more quickly.

5 questions test this
Descriptions persist as metadata and power search and discovery

Because comments persist as Unity Catalog metadata they survive schema evolution and surface in Catalog Explorer search and AI/BI Genie, letting users find and understand data without opening the underlying files.

Governed tags are the account-level attribute vocabulary ABAC builds on

Governed tags are a centrally defined, account-level set of tag keys and allowed values, with permissions controlling who may apply each tag; they are the attributes that attribute-based access control policies evaluate to decide protection.

10 questions test this
An ABAC policy applies filters or masks automatically to every tag-matched object

An attribute-based access control (ABAC) policy is attached at a catalog, schema, or table and uses governed-tag conditions to apply a row filter or column mask to every current and future object carrying the matching tag, so one policy governs many tables at once.

Trap ABAC scales a single tag-driven policy across many tables; a table-level SET MASK or SET ROW FILTER must be configured on each table individually.

10 questions test this
Tags assigned to a parent object are inherited by child objects

A governed tag applied to a catalog or schema is inherited by the schemas and tables beneath it, but not by individual table columns, so tagging a parent propagates the attribute that ABAC policies and discovery rely on to descendant tables; a column-level classification must be tagged on the column directly.

A row filter removes whole rows via ALTER TABLE ... SET ROW FILTER

A row filter is a boolean SQL UDF attached with ALTER TABLE SET ROW FILTER; the function is evaluated per row and returns TRUE to keep the row or FALSE/NULL to drop it, so it controls which entire rows a principal sees at query time.

Trap A row filter removes whole rows and cannot reveal only part of a column value; use a column mask for partial redaction.

19 questions test this
A column mask redacts values via ALTER TABLE ... ALTER COLUMN ... SET MASK

A column mask is a SQL UDF attached with ALTER TABLE ALTER COLUMN SET MASK; it rewrites each returned value at query time, for example showing only the text after the @ in an email or only the last four digits of a card, while every row is still returned.

Trap Masking only sensitive columns while keeping table SELECT follows least privilege and lets queries run without errors, unlike revoking column access.

19 questions test this
Row filters and column masks attach to base tables, not to standard views

Table-level row filters and column masks are attached to base tables and cannot be placed on a standard view, while ABAC policies extend the same row-filter and column-mask protection to materialized views and streaming tables; once attached they are enforced for every query through any SQL warehouse, notebook, or client.

delta.deletedFileRetentionDuration sets the VACUUM retention window

The table property delta.deletedFileRetentionDuration defines how long removed data files are retained before VACUUM is permitted to delete them, defaulting to 7 days; raising it lengthens the window during which older versions stay recoverable.

18 questions test this
delta.logRetentionDuration bounds how far back time travel can go

The table property delta.logRetentionDuration controls how long transaction-log history is kept, defaulting to 30 days, which bounds the versions and timestamps that time-travel queries can reference.

18 questions test this
Running VACUUM permanently deletes old files and forfeits earlier time travel

VACUUM permanently removes data files that are no longer referenced by the latest table state and are older than the retention threshold, after which you can no longer time-travel to a version whose files were purged, trading storage cost against recoverability.

Unity Catalog captures lineage automatically down to the column level

For queries and workflows run on Azure Databricks, Unity Catalog captures runtime data lineage automatically down to the column level with no configuration, and aggregates it across every workspace attached to the metastore.

10 questions test this
Catalog Explorer shows owner, history, dependencies, and upstream/downstream lineage

The Catalog Explorer Lineage tab renders an interactive graph of upstream and downstream tables, columns, notebooks, jobs, and dashboards alongside the object owner and history, so you can trace dependencies before changing or deleting an object.

13 questions test this
Unity Catalog audit events are queryable in the system.access.audit table

The system.access.audit system table records account- and workspace-level audit events, capturing which principal accessed which securable and what action was taken, and retains them for up to one year for security and compliance analysis.

7 questions test this
Azure diagnostic settings deliver Databricks audit logs to Log Analytics

Configuring Azure diagnostic settings on the workspace streams Azure Databricks diagnostic (audit) logs to a Log Analytics workspace, a storage account, or Event Hubs for long-term retention, querying, and alerting in Azure Monitor.

6 questions test this
Verbose audit logging adds notebook and SQL command events

Enabling verbose audit logging records additional fine-grained events such as commandSubmit, commandFinish, and runCommand, capturing notebook-cell and SQL-warehouse command activity that standard audit logging omits.

Databricks-to-Databricks sharing needs no token when the recipient has Unity Catalog

When the recipient also has a Unity Catalog-enabled workspace, a recipient of authentication type DATABRICKS shares data over a secure Databricks-managed channel identified by a sharing identifier, so no bearer token is created or managed and identity, authentication, and auditing are handled by the platform.

Trap Databricks-to-Databricks sharing eliminates token management; only open sharing to a non-Databricks recipient issues a bearer token.

12 questions test this
Open sharing uses a bearer token and credential file for non-Databricks recipients

Open sharing (the Databricks-to-Open protocol) reaches recipients on any platform by authenticating a recipient of type TOKEN using a long-lived bearer token or OIDC (OpenID Connect) federation, where the recipient presents a short-lived token minted by its own identity provider instead of a stored Databricks credential; for a token, Databricks generates a credential file delivered via an activation link that must be secured and rotated.

14 questions test this
A secure share exposes only selected tables to a named recipient

A secure OpenSharing (previously Delta Sharing) strategy creates a share, adds only the specific tables or views to be exposed, and grants that share to a defined recipient, so the recipient receives read-only access to just the shared objects rather than to the whole metastore. OpenSharing names the feature; its two recipient modes are Databricks-to-Databricks sharing, which needs no token, and open sharing (the Databricks-to-Open protocol), which issues one.

A share partition filter written against CURRENT_RECIPIENT lets one share deliver a different row slice to each recipient

When a table is added to a share you can supply a partition specification that references a recipient property instead of a literal, for example ALTER SHARE acme ADD TABLE acme.default.some_table PARTITION (country = CURRENT_RECIPIENT().country). Databricks then delivers to each recipient only the rows whose column value equals that recipient's property value, so the same share and the same table can be granted to many recipients across different accounts, workspaces and metastores while data boundaries are preserved. The documentation states that without this parameterized partition sharing you would have to create a separate share for each recipient.

Trap Believing that giving two partners different row subsets of the same table requires two shares (or two derived tables), because a share is a static list of objects and cannot be evaluated per recipient.

3 questions test this
The predefined databricks.accountId and databricks.metastoreId recipient properties exist only for Databricks-to-Databricks recipients

Every recipient object carries predefined properties that begin with 'databricks.': databricks.accountId and databricks.metastoreId identify the recipient's Databricks account and Unity Catalog metastore and are documented as Databricks-to-Databricks sharing ONLY, while databricks.name is simply the recipient's name and is the property surfaced for open (token-authenticated) recipients. Any additional key you need for filtering must be created as a custom property, either at creation time with CREATE RECIPIENT ... PROPERTIES ('country' = 'us') or afterwards with ALTER RECIPIENT ... SET PROPERTIES / UNSET PROPERTIES. So a design that partitions shared data by Databricks account ID works only when every recipient is on Unity Catalog; an open recipient needs a custom property instead.

Trap Assuming databricks.accountId or databricks.metastoreId can be used to partition data for a non-Databricks (bearer-token / open sharing) recipient, since the recipient object exists in both sharing modes.

1 question tests this
Per-recipient COLUMN redaction requires a shared dynamic view; a share partition filter can only include or exclude whole rows

A share partition filter expresses a single equality between a table column and a recipient property, so it can withhold rows but cannot alter the value a recipient sees in a column. To vary column values per recipient the provider creates a view whose definition calls CURRENT_RECIPIENT('') inside a CASE expression — for example returning the pii column when CURRENT_RECIPIENT('country') = 'US' and the literal 'REDACTED' otherwise — and then adds that view to the share exactly as a normal view. The same function also supports row-level predicates in a view (WHERE country = CURRENT_RECIPIENT('country')), and providers cannot create another view that references a dynamic view.

Trap Believing a share partition filter can mask or redact a sensitive column per recipient, rather than only filtering which rows are delivered.

3 questions test this
A provider cannot validate a CURRENT_RECIPIENT view by querying it directly, because outside a sharing context the function has no value to return

A view that calls CURRENT_RECIPIENT is for sharing only: when the provider selects from it in their own workspace the function evaluation fails for lack of a sharing context, so the query errors rather than returning unfiltered data. The two documented ways to test it are to mock the context in the session with SET RECIPIENT , which sets CURRENT_RECIPIENT for that session, or to share the view with yourself and query it as a recipient.

Trap Assuming the provider can smoke-test a dynamic view by simply running SELECT * on it before sharing, and that the result would show the unfiltered base rows.

1 question tests this
Row filter and column mask UDFs run with definer's rights, except user-context functions which evaluate as the invoker

The documentation states that all filters run with definer's rights except for functions that check user context — for example SESSION_USER and IS_ACCOUNT_GROUP_MEMBER — which run as the invoker. That combination is what makes the mapping-table (access-control-list) pattern work: a filter such as RETURN EXISTS(SELECT 1 FROM valid_users v WHERE v.username = SESSION_USER()) reads the entitlement table under the function definer's rights while still resolving the identity of whoever ran the query, so the querying user does not need to be granted access to the entitlement table itself.

Trap Concluding that a mapping-table-driven row filter fails unless every end user is also granted SELECT on the mapping table, since the filter reads that table during their query.

2 questions test this
A UDF parameter type that does not match its column is implicitly cast, and with ANSI mode off uncastable values become NULL, silently defeating the filter

The data type of each table column passed to a row filter or column mask must match the corresponding UDF parameter type; on a mismatch Databricks implicitly casts the column value. With spark.sql.ansi.enabled = false, values that cannot be cast are converted to NULL with no error raised, so a filter written as RETURN dept IS NULL over a STRING column bound to an INT parameter evaluates to true for every row and the query returns the entire table. Databricks recommends enabling ANSI mode so a failed cast raises an error and the defect is visible instead of silently returning the wrong rows or masking the wrong values.

Trap Assuming a type mismatch between the column and the UDF parameter is always caught at ALTER TABLE time or raises an error at query time, so a filter can never silently fail open.

3 questions test this
Reading a filtered or masked table requires a SQL warehouse, standard access mode, or dedicated access mode on a recent LTS runtime or serverless compute with serverless enabled

To query a table carrying a row filter or a column mask the compute must be a SQL warehouse, standard access mode on a supported Databricks Runtime, or dedicated access mode on a more recent long-term-support runtime - and dedicated access mode additionally requires the workspace to be enabled for serverless compute, because the fine-grained access control that enforces the policy runs on serverless and can incur serverless charges. Dedicated compute on a runtime below that floor cannot read such a table at all, writing from dedicated compute needs a newer runtime still, and a runtime below the supported floor fails SECURELY: it returns no data rather than returning the table unfiltered.

Trap Believing that because Unity Catalog enforces the policy centrally, any Unity Catalog-enabled cluster can read the table - and that an unsupported runtime would fall back to showing the unfiltered rows.

2 questions test this
Dropping the filter or mask UDF before detaching it from the table leaves the table in an inaccessible state

The policy must be removed from the table first — ALTER TABLE DROP ROW FILTER, or ALTER TABLE ALTER COLUMN DROP MASK — and only then DROP FUNCTION. If the function is dropped first the table is left holding an orphaned policy reference and becomes inaccessible; recovery is to run the same ALTER TABLE ... DROP ROW FILTER / DROP MASK statement to clear the dangling reference. To change the logic without any of this, use CREATE OR REPLACE FUNCTION, which leaves the attachment intact.

Trap Expecting that dropping the masking or filtering UDF automatically detaches the policy and returns the table to unfiltered, fully readable behaviour.

1 question tests this
Data Classification is enabled per catalog by its owner or a MANAGE holder, and only a future-inclusive schema scope keeps schemas created later under scan

A catalog owner, or a principal holding MANAGE on the catalog, turns Data Classification on for that catalog, which starts an incremental background scan of its tables and records each detection as a system governed tag for the sensitive class found. The schema scope chosen at enablement decides what happens next: a scope covering selected and future schemas keeps every schema added to the catalog afterwards in the scan, while a scope limited to only the schemas selected at that moment leaves every later schema unscanned until someone reopens the configuration. Choose the future-inclusive scope whenever the requirement is that newly created data be discovered without ongoing manual configuration, and remember that enabling classification on one catalog says nothing about other catalogs in the metastore.

Trap Believing that once Data Classification is enabled on a catalog everything beneath it is permanently covered, so schemas created after enablement are scanned regardless of which schema scope was selected.

2 questions test this
Data Classification finds and labels sensitive columns but does not restrict access to them, so a requirement that a group must not see the values still needs a masking control

The output of a classification scan is a governed tag recording that a sensitive class was detected in a column; the tag changes discovery and policy targeting, not who can read the data. A requirement that a group must not see sensitive values is still met by a masking control — an attribute-based access control policy, a column mask, or a secure view — with classification supplying the tags that control matches on. Read the requirement in the other direction too: classification is the right answer when newly created tables must be found without anyone hand-building an inventory of sensitive columns, and views and metric views are never scanned, so a view over sensitive data is addressed by classifying its underlying tables.

Trap Treating enablement of the scan as the access control itself — answering that turning Data Classification on stops an analyst group from reading the columns it detected as PII.

2 questions test this
Automatic tagging of detected columns is a separate switch from classification, with its own privilege set and a catalog setting that overrides the metastore default

Starting the scan and applying the detected class tags are two different settings: tagging additionally requires USE CATALOG and APPLY TAG on the catalog plus ASSIGN on the tag being applied, and the classification system tags are account-admin-controlled by default, so a data steward who can enable the scan may still be unable to enable tagging. A catalog-level tagging setting overrides the metastore-level default, which is how one catalog can tag automatically while the rest of the metastore does not. Turning tagging on tags existing detections on the next scan rather than backfilling them at once, and turning it off stops future tags without removing the tags already applied.

Trap Assuming whoever can enable Data Classification on a catalog can also enable automatic tagging, and that flipping tagging on immediately tags every column already detected while flipping it off removes them.

3 questions test this
Notebook files, Unity Catalog volumes and Unity Catalog models travel only over the Databricks-to-Databricks protocol, so a recipient without Unity Catalog can be given tabular assets only

What a share may carry is decided by the recipient's protocol, not by how the share is built: a recipient on their own Unity Catalog metastore can receive notebooks, volumes and models alongside tables and views, while an open-protocol recipient reached through a credential file can receive tabular assets only. A requirement to hand a non-Databricks partner raw files or a notebook is therefore not satisfied by adding those assets to the share and needs a different delivery path. Views, materialized views and streaming tables are shareable, but an open recipient receives only the current snapshot with no time travel, streaming read or change data feed, and the provider materializes and filters those assets at its own cost — which is what makes a curated view an expensive answer to a cheap requirement.

Trap Believing a volume or a notebook added to the share will reach any recipient once they hold the credential file, since a credential file is all an external partner needs to read shared tables.

3 questions test this
Sharing a table WITH HISTORY is what lets the recipient time travel, stream from it and run transactions, and it is mandatory for tables using deletion vectors or column mapping

The history option is chosen from what the consumer must be able to do: without history the recipient sees the current state only, and with history they can query earlier versions, consume the table as a Structured Streaming source, and run transactional reads. Change data feed must already be enabled on the table before it is shared with history for the recipient's change queries to return anything, so enabling it after the fact does not retroactively serve them. A table that uses deletion vectors or column mapping cannot be shared at all unless it is shared with history.

Trap Assuming a recipient can time travel or run an incremental stream against any shared Delta table because the provider's transaction log still holds the older versions, making the history option a storage-cost decision rather than a capability decision.

3 questions test this
Adding a whole schema to a share includes assets added to it later and always shares full history, but it forfeits table aliases and partition specifications

Schema-level granularity is the right choice when the consumer should keep receiving whatever lands in that schema, because every supported asset added afterwards joins the share automatically and everything travels with history. The cost is that the schema itself cannot be aliased and no table inside it can be given an alias or a partition specification. A requirement to expose one table under a different name, or to expose only certain partitions of it, therefore forces asset-by-asset sharing instead of the convenience of adding the schema.

Trap Expecting to add the whole schema for convenience and then alias or partition-restrict one table inside it, as if the two granularities could be mixed on the same shared object.

3 questions test this

References

  1. COMMENT ON
  2. Add comments to data and AI assets
  3. Add AI-generated comments to Unity Catalog objects
  4. Row filters and column masks
  5. Create a dynamic view
  6. Attribute-based access control in Unity Catalog
  7. Governed tags
  8. When to use ABAC vs table-level row filters and column masks
  9. Lineage in Unity Catalog
  10. Audit log system table reference
  11. System tables reference
  12. Configure diagnostic log delivery
  13. Enable verbose audit logs
  14. Table properties reference
  15. Remove unused data files with vacuum
  16. What is OpenSharing?
  17. Create data recipients for OpenSharing (Databricks-to-Databricks sharing)
  18. Create a recipient object for non-Databricks users using bearer tokens (Databricks-to-Open sharing)