Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ whereClause, found := clickhouse.Find(stmt, func(node clickhouse.Expr) bool {
})
```

## Row policies

`CREATE`, `ALTER`, and `DROP [ROW] POLICY` have dedicated AST nodes. Policy inspection supports `SHOW CREATE [ROW] POLICY` and `SHOW [ROW] POLICIES`.

See [row-policy syntax and AST fields](docs/row-policies.md) for target bindings, principal sets, and the distinction between an omitted ALTER clause and an explicit `NONE`.

## Update test assets

For the files inside `output` and `format` dir are generated by the test cases,
Expand Down
69 changes: 69 additions & 0 deletions docs/row-policies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Row policies

The parser supports `CREATE`, `ALTER`, and `DROP [ROW] POLICY`, plus `SHOW CREATE [ROW] POLICY` and `SHOW [ROW] POLICIES`. These produce typed AST nodes rather than opaque SQL strings. Parsing does not execute policies, resolve users or roles, or check whether a table exists.

```sql
CREATE ROW POLICY example_policy
ON db.example_table, db.example_table_local
AS PERMISSIVE
FOR SELECT USING id > 0
TO example_role;

ALTER ROW POLICY example_policy ON db.example_table
USING NONE TO NONE;

DROP ROW POLICY IF EXISTS example_policy
ON db.example_table, db.example_table_local;

SHOW CREATE ROW POLICY example_policy ON db.example_table;
SHOW ROW POLICIES ON db.*;
```

## Target bindings

`Targets` contains explicit `RowPolicyTarget` nodes. Each binds one `PolicyName` to a `TableIdentifier`.

The following forms are supported:

```sql
CREATE POLICY p1, p2 ON db.t USING 1 TO reader;
CREATE POLICY p ON db.t, other.t USING 1 TO reader;
CREATE POLICY p1 ON db.t, p2 ON other.t USING 1 TO reader;
```

A multi-name list cannot also have a multi-table target list. `p1, p2 ON t1, t2` is not a Cartesian product and is rejected.

Database policies use `db.*`, or `*` for the current database. A quoted table named `*` remains distinct from a wildcard. Policy declarations reject prefix wildcards and wildcard database names rather than silently narrowing them. `SHOW [CREATE] ROW POLICIES ON *.*` can inspect all policies.

`ON CLUSTER` is a statement-level clause. CREATE/ALTER can select an access storage with `IN`; DROP uses `FROM`.

## ALTER presence semantics

`CreateRowPolicy` and `AlterRowPolicy` embed `RowPolicyOptions`. The options retain omitted fields because omission on ALTER means keeping the existing value.

- `Mode == ""` means omitted. `RowPolicyPermissive` and `RowPolicyRestrictive` are explicit modes.
- No `Filters` means no filter update. Each `RowPolicyFilter` preserves the explicit `FOR` command list in `Commands`; an empty list means the clause was omitted. `Using` and `WithCheck` conditions are optional. A condition with `None == true` clears that condition; an expression containing zero is still an expression.
- `To == nil` means omitted. A non-nil `RowPolicySubjects` with no principals and `All == false` represents `TO NONE`.
- `RenameTo` is only available on ALTER and requires exactly one target.

CREATE's `OR REPLACE` is different from ALTER. Consumers must not interpret omitted CREATE fields as instructions to preserve the previous policy.

Repeated filter clauses remain ordered in `Filters`. They are not collapsed into a single expression.

## Principal sets

`RowPolicySubjects` represents `TO`, including named users/roles, `ALL`, `NONE`, `EXCEPT`, and `CURRENT_USER`. Dynamic current-user aliases normalize to `CURRENT_USER`; quoted principals with the same spelling remain names.

A `RowPolicyPrincipal` contains either `Name` and an optional `Host`, or `CurrentUser == true`. A complete single-quoted principal name can contain `@`; a separate host suffix follows an identifier, as in `user1@'localhost'` or a backtick-quoted identifier followed by `@'localhost'`.

## Filtering scope and traversal

ClickHouse currently implements SELECT row filtering. The parser preserves an omitted `FOR` clause, explicit `FOR SELECT`, and explicit `FOR ALL` rather than adding or replacing the clause during formatting. `FOR INSERT`, `FOR UPDATE`, and `FOR DELETE` are rejected.

The parser retains `WITH CHECK` syntax as a separate condition when present. That does not imply that ClickHouse enforces write-row checks. Consumers should validate the enforcement capabilities of their target server.

Filter expressions are visible through both `Accept`/`ASTVisitor` and `Walk`. These APIs inspect syntax; consumers must not evaluate request-dependent functions such as `getSetting` or `currentUser` while rewriting policy DDL.

Custom `ASTVisitor` implementations need the new policy visit methods. Embedding `DefaultASTVisitor` supplies the default methods.

Internal `ATTACH ROW POLICY` access-storage serialization is not part of the supported SQL statement grammar.
Loading
Loading