Skip to content

Commit 8bc5ee8

Browse files
refine column masking.
1 parent 24edd34 commit 8bc5ee8

File tree

12 files changed

+524
-244
lines changed

12 files changed

+524
-244
lines changed

docs/static/rest-catalog-open-api.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2921,12 +2921,12 @@ components:
29212921
properties:
29222922
filter:
29232923
type: array
2924-
description: Additional row-level filter as JSON strings. Each element should be a JSON object containing a 'filter' field.
2924+
description: Additional row-level filter as Predicate entry strings.
29252925
items:
29262926
type: string
29272927
columnMasking:
29282928
type: object
2929-
description: Column masking rules as a map from column name to predicate entry JSON string (TransformPredicate).
2929+
description: Column masking rules as a map from column name to Transform entry JSON string.
29302930
additionalProperties:
29312931
type: string
29322932
AlterDatabaseRequest:

paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ public void alterTable(Identifier identifier, List<SchemaChange> changes) {
672672
*
673673
* @param identifier database name and table name.
674674
* @param select select columns, null if select all
675-
* @return auth result including additional row-level filter and optional column masking
675+
* @return additional row-level filter and column masking
676676
* @throws NoSuchResourceException Exception thrown on HTTP 404 means the table not exists
677677
* @throws ForbiddenException Exception thrown on HTTP 403 means don't have the permission for
678678
* this table

paimon-api/src/main/java/org/apache/paimon/rest/responses/AuthTableQueryResponse.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public class AuthTableQueryResponse implements RESTResponse {
4040
@JsonProperty(FIELD_FILTER)
4141
private final List<String> filter;
4242

43+
@JsonInclude(JsonInclude.Include.NON_NULL)
44+
@JsonProperty(FIELD_COLUMN_MASKING)
45+
private final Map<String, String> columnMasking;
46+
4347
@JsonCreator
4448
public AuthTableQueryResponse(
4549
@JsonProperty(FIELD_FILTER) List<String> filter,
@@ -53,10 +57,6 @@ public List<String> filter() {
5357
return filter;
5458
}
5559

56-
@JsonInclude(JsonInclude.Include.NON_NULL)
57-
@JsonProperty(FIELD_COLUMN_MASKING)
58-
private final Map<String, String> columnMasking;
59-
6060
@JsonGetter(FIELD_COLUMN_MASKING)
6161
public Map<String, String> columnMasking() {
6262
return columnMasking;

paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,12 +1032,12 @@ void alterFunction(
10321032
// ==================== Table Auth ==========================
10331033

10341034
/**
1035-
* Auth table query select and get the row-level filter and column masking rules.
1035+
* Auth table query select and get the filter for row level access control and column masking
1036+
* rules.
10361037
*
10371038
* @param identifier path of the table to alter partitions
10381039
* @param select selected fields, null if select all
1039-
* @return auth result including additional filter for row level access control and column
1040-
* masking
1040+
* @return additional filter for row level access control and column masking
10411041
* @throws TableNotExistException if the table does not exist
10421042
*/
10431043
TableQueryAuthResult authTableQuery(Identifier identifier, @Nullable List<String> select)

paimon-core/src/main/java/org/apache/paimon/catalog/TableQueryAuthResult.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
package org.apache.paimon.catalog;
2020

2121
import org.apache.paimon.predicate.Predicate;
22-
import org.apache.paimon.predicate.TransformPredicate;
22+
import org.apache.paimon.predicate.Transform;
2323

2424
import javax.annotation.Nullable;
2525

@@ -30,10 +30,10 @@
3030
public class TableQueryAuthResult {
3131

3232
@Nullable private final Predicate rowFilter;
33-
private final Map<String, TransformPredicate> columnMasking;
33+
private final Map<String, Transform> columnMasking;
3434

3535
public TableQueryAuthResult(
36-
@Nullable Predicate rowFilter, Map<String, TransformPredicate> columnMasking) {
36+
@Nullable Predicate rowFilter, Map<String, Transform> columnMasking) {
3737
this.rowFilter = rowFilter;
3838
this.columnMasking = columnMasking == null ? Collections.emptyMap() : columnMasking;
3939
}
@@ -47,7 +47,7 @@ public Predicate rowFilter() {
4747
return rowFilter;
4848
}
4949

50-
public Map<String, TransformPredicate> columnMasking() {
50+
public Map<String, Transform> columnMasking() {
5151
return columnMasking;
5252
}
5353
}

paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import org.apache.paimon.predicate.And;
4242
import org.apache.paimon.predicate.CompoundPredicate;
4343
import org.apache.paimon.predicate.Predicate;
44-
import org.apache.paimon.predicate.TransformPredicate;
44+
import org.apache.paimon.predicate.Transform;
4545
import org.apache.paimon.rest.exceptions.AlreadyExistsException;
4646
import org.apache.paimon.rest.exceptions.BadRequestException;
4747
import org.apache.paimon.rest.exceptions.ForbiddenException;
@@ -66,6 +66,7 @@
6666
import org.apache.paimon.utils.Pair;
6767
import org.apache.paimon.utils.PredicateJsonSerde;
6868
import org.apache.paimon.utils.SnapshotNotExistException;
69+
import org.apache.paimon.utils.TransformJsonSerde;
6970
import org.apache.paimon.view.View;
7071
import org.apache.paimon.view.ViewChange;
7172
import org.apache.paimon.view.ViewImpl;
@@ -559,7 +560,7 @@ public TableQueryAuthResult authTableQuery(Identifier identifier, @Nullable List
559560
}
560561
}
561562

562-
Map<String, TransformPredicate> columnMasking = new TreeMap<>();
563+
Map<String, Transform> columnMasking = new TreeMap<>();
563564
Map<String, String> maskingJsons = response == null ? null : response.columnMasking();
564565
if (maskingJsons != null && !maskingJsons.isEmpty()) {
565566
for (Map.Entry<String, String> e : maskingJsons.entrySet()) {
@@ -571,18 +572,10 @@ public TableQueryAuthResult authTableQuery(Identifier identifier, @Nullable List
571572
|| json.trim().isEmpty()) {
572573
continue;
573574
}
574-
Predicate predicate = PredicateJsonSerde.parse(json);
575-
if (predicate == null) {
576-
continue;
577-
}
578-
if (!(predicate instanceof TransformPredicate)) {
579-
throw new IllegalArgumentException(
580-
"Column masking must be a TransformPredicate, but got "
581-
+ predicate.getClass().getName()
582-
+ " for column "
583-
+ column);
575+
Transform transform = TransformJsonSerde.parse(json);
576+
if (transform != null) {
577+
columnMasking.put(column, transform);
584578
}
585-
columnMasking.put(column, (TransformPredicate) predicate);
586579
}
587580
}
588581

paimon-core/src/main/java/org/apache/paimon/table/source/MaskingTableRead.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import org.apache.paimon.disk.IOManager;
2424
import org.apache.paimon.metrics.MetricRegistry;
2525
import org.apache.paimon.predicate.FieldRef;
26-
import org.apache.paimon.predicate.TransformPredicate;
26+
import org.apache.paimon.predicate.Transform;
2727
import org.apache.paimon.reader.RecordReader;
2828
import org.apache.paimon.types.DataType;
2929
import org.apache.paimon.types.RowType;
@@ -45,11 +45,11 @@ public class MaskingTableRead implements TableRead {
4545

4646
private final TableRead wrapped;
4747
private final RowType outputRowType;
48-
private final Map<String, TransformPredicate> masking;
48+
private final Map<String, Transform> masking;
4949
private final MaskingApplier applier;
5050

5151
public MaskingTableRead(
52-
TableRead wrapped, RowType outputRowType, Map<String, TransformPredicate> masking) {
52+
TableRead wrapped, RowType outputRowType, Map<String, Transform> masking) {
5353
this.wrapped = wrapped;
5454
this.outputRowType = outputRowType;
5555
this.masking = masking;
@@ -105,9 +105,9 @@ public void close() throws IOException {
105105
private static class MaskingApplier {
106106

107107
private final RowType outputRowType;
108-
private final Map<Integer, TransformPredicate> remapped;
108+
private final Map<Integer, Transform> remapped;
109109

110-
private MaskingApplier(RowType outputRowType, Map<String, TransformPredicate> masking) {
110+
private MaskingApplier(RowType outputRowType, Map<String, Transform> masking) {
111111
this.outputRowType = outputRowType;
112112
this.remapped = remapToOutputRow(outputRowType, masking);
113113
}
@@ -122,26 +122,26 @@ private InternalRow apply(InternalRow row) {
122122
DataType type = outputRowType.getTypeAt(i);
123123
out.setField(i, get(row, i, type));
124124
}
125-
for (Map.Entry<Integer, TransformPredicate> e : remapped.entrySet()) {
125+
for (Map.Entry<Integer, Transform> e : remapped.entrySet()) {
126126
int targetIndex = e.getKey();
127-
TransformPredicate predicate = e.getValue();
128-
Object masked = predicate.transform().transform(row);
127+
Transform transform = e.getValue();
128+
Object masked = transform.transform(row);
129129
out.setField(targetIndex, masked);
130130
}
131131
return out;
132132
}
133133

134-
private static Map<Integer, TransformPredicate> remapToOutputRow(
135-
RowType outputRowType, Map<String, TransformPredicate> masking) {
136-
Map<Integer, TransformPredicate> out = new HashMap<>();
134+
private static Map<Integer, Transform> remapToOutputRow(
135+
RowType outputRowType, Map<String, Transform> masking) {
136+
Map<Integer, Transform> out = new HashMap<>();
137137
if (masking == null || masking.isEmpty()) {
138138
return out;
139139
}
140140

141-
for (Map.Entry<String, TransformPredicate> e : masking.entrySet()) {
141+
for (Map.Entry<String, Transform> e : masking.entrySet()) {
142142
String targetColumn = e.getKey();
143-
TransformPredicate predicate = e.getValue();
144-
if (targetColumn == null || predicate == null) {
143+
Transform transform = e.getValue();
144+
if (targetColumn == null || transform == null) {
145145
continue;
146146
}
147147

@@ -151,7 +151,7 @@ private static Map<Integer, TransformPredicate> remapToOutputRow(
151151
}
152152

153153
List<Object> newInputs = new ArrayList<>();
154-
for (Object input : predicate.transform().inputs()) {
154+
for (Object input : transform.inputs()) {
155155
if (input instanceof FieldRef) {
156156
FieldRef ref = (FieldRef) input;
157157
int newIndex = outputRowType.getFieldIndex(ref.name());
@@ -168,7 +168,7 @@ private static Map<Integer, TransformPredicate> remapToOutputRow(
168168
newInputs.add(input);
169169
}
170170
}
171-
out.put(targetIndex, predicate.copyWithNewInputs(newInputs));
171+
out.put(targetIndex, transform.copyWithNewInputs(newInputs));
172172
}
173173
return out;
174174
}

0 commit comments

Comments
 (0)