JingsongLi commented on code in PR #10950:
URL: https://github.com/apache/paimon/pull/10950#discussion_r4443107295


##########
paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/expressions/ExpressionUtils.scala:
##########
@@ -18,5 +18,42 @@
 
 package org.apache.paimon.spark.catalyst.analysis.expressions
 
+import org.apache.paimon.predicate.Predicate
+import org.apache.paimon.types.RowType
+
+import org.apache.spark.sql.SparkSession
+import org.apache.spark.sql.catalyst.optimizer.{ConstantFolding, SimplifyCasts}
+import org.apache.spark.sql.catalyst.plans.logical.Filter
+import org.apache.spark.sql.catalyst.trees.TreePattern.CURRENT_LIKE
+import org.apache.spark.sql.execution.datasources.v2.DataSourceV2Relation
+
 /** This wrapper is only used in java code, e.g. Procedure. */
-object ExpressionUtils extends ExpressionHelper
+object ExpressionUtils extends ExpressionHelper {
+
+  def convertPolicyFilter(
+      spark: SparkSession,
+      relation: DataSourceV2Relation,
+      rowType: RowType,
+      filterSql: String): Predicate = {
+    val parsed = spark.sessionState.sqlParser.parseExpression(filterSql)
+    val analyzed = spark.sessionState.analyzer.execute(Filter(parsed, 
relation))
+    spark.sessionState.analyzer.checkAnalysis(analyzed)
+    val filter = analyzed.asInstanceOf[Filter]
+    val condition = filter.condition
+    // Query-context values must not be frozen into a persistent authorization 
rule.
+    require(
+      !condition.containsPattern(CURRENT_LIKE),
+      "filter_sql cannot contain expressions that depend on the current query 
context."
+    )
+
+    val normalized = 
SimplifyCasts(ConstantFolding(filter)).asInstanceOf[Filter].condition
+    // A stored policy has no engine-side residual filter, so every conjunct 
must convert.
+    convertConditionToPaimonPredicate(

Review Comment:
   [P1] Require exact SQL semantics before storing a converted policy
   
   `ignorePartialFailure = false` proves that every expression can be 
converted, but does not prove semantic equivalence. I reproduced an 
unauthorized row through the actual REST policy/read path on this head: create 
`(id INT, v DOUBLE)` with `query-auth.enabled=true`, insert `(1, CAST('-0.0' AS 
DOUBLE)), (2, 0.0), (3, 1.0)`, and create a ROW_FILTER with `filter_sql => 'v 
<> CAST(0 AS DOUBLE)'`. Spark's evaluation over an independent VALUES relation 
returns only id 3; selecting from the policy-protected table returns ids 1 and 
3. The generated NotEqual calls CompareUtils/Double.compareTo, which 
distinguishes the two signs of zero, whereas Spark SQL considers them equal. 
The persisted policy has no Spark residual to remove the extra row. FLOAT has 
the same comparison boundary. Please reject conversions without exact policy 
semantics or supply an exact conversion (including signed-zero comparisons), 
and add a real authorization regression test whose expected result is evaluated 
indepen
 dently of Paimon pushdown.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to