blob: 5a546d284868a37d6b6d0cf3797871e51aa3106d [file]
################################################################################
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################
from typing import Callable, Dict, List, Optional
import pyarrow as pa
import pyarrow.compute as pc
from pypaimon.common.predicate_json_parser import (
extract_referenced_fields,
parse_predicate_to_batch_filter,
)
from pypaimon.read.plan import Plan
from pypaimon.read.query_auth_split import QueryAuthSplit
from pypaimon.schema.data_types import DataField
class TableQueryAuthResult:
def __init__(self, filter: Optional[List[str]], column_masking: Optional[Dict[str, str]]):
self.filter = [f for f in filter if f] if filter else filter
self.column_masking = (
{k: v for k, v in column_masking.items() if k and v}
if column_masking else column_masking
)
@property
def has_restrictions(self):
return bool(self.filter) or bool(self.column_masking)
def convert_plan(self, plan):
if not self.has_restrictions:
return plan
auth_splits = [QueryAuthSplit(split, self) for split in plan.splits()]
return Plan(auth_splits, snapshot_id=plan.snapshot_id)
def extract_row_filter(self) -> Optional[Callable[[pa.RecordBatch], pa.Array]]:
if not self.filter:
return None
filters = [parse_predicate_to_batch_filter(json_str) for json_str in self.filter]
if len(filters) == 1:
return filters[0]
def combined(batch: pa.RecordBatch) -> pa.Array:
result = filters[0](batch)
for f in filters[1:]:
result = pc.and_(result, f(batch))
return result
return combined
def get_extra_fields_for_filter(
self,
read_fields: List[DataField],
table_fields: List[DataField],
) -> List[DataField]:
if not self.filter:
return []
read_field_names = {f.name for f in read_fields}
extra = []
for json_str in self.filter:
referenced = extract_referenced_fields(json_str)
for name in referenced:
if name not in read_field_names:
field = next((f for f in table_fields if f.name == name), None)
if field:
extra.append(field)
read_field_names.add(name)
return extra