diff --git a/extensions/spark/kyuubi-spark-authz/src/main/resources/table_command_spec.json b/extensions/spark/kyuubi-spark-authz/src/main/resources/table_command_spec.json index 4442e6868a6..583ad29b4e6 100644 --- a/extensions/spark/kyuubi-spark-authz/src/main/resources/table_command_spec.json +++ b/extensions/spark/kyuubi-spark-authz/src/main/resources/table_command_spec.json @@ -2198,7 +2198,11 @@ "fieldName" : "source", "fieldExtractor" : "LogicalPlanQueryExtractor" } ], - "uriDescs" : [ ] + "uriDescs" : [ { + "fieldName" : "target", + "fieldExtractor" : "SubqueryAliasURIExtractor", + "isInput" : false + } ] }, { "classname" : "org.apache.spark.sql.delta.commands.OptimizeTableCommand", "tableDescs" : [ { diff --git a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/tableExtractors.scala b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/tableExtractors.scala index 82448f9cdad..57f0a8e4e87 100644 --- a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/tableExtractors.scala +++ b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/tableExtractors.scala @@ -257,11 +257,15 @@ class ResolvedIdentifierTableExtractor extends TableExtractor { class SubqueryAliasTableExtractor extends TableExtractor { override def apply(spark: SparkSession, v1: AnyRef): Option[Table] = { v1.asInstanceOf[SubqueryAlias] match { - case SubqueryAlias(_, SubqueryAlias(identifier, _)) - if !isPathIdentifier(identifier.name, spark) => - lookupExtractor[StringTableExtractor].apply(spark, identifier.toString()) + case SubqueryAlias(_, SubqueryAlias(identifier, _)) => + if (isPathIdentifier(identifier.name, spark)) { + None + } else { + lookupExtractor[StringTableExtractor].apply(spark, identifier.toString()) + } case SubqueryAlias(identifier, _) if !isPathIdentifier(identifier.name, spark) => lookupExtractor[StringTableExtractor].apply(spark, identifier.toString()) + case _ => None } } } diff --git a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/uriExtractors.scala b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/uriExtractors.scala index eff8427462d..cf59a5c6398 100644 --- a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/uriExtractors.scala +++ b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/uriExtractors.scala @@ -109,11 +109,15 @@ class IdentifierURIExtractor extends URIExtractor { class SubqueryAliasURIExtractor extends URIExtractor { override def apply(spark: SparkSession, v1: AnyRef): Seq[Uri] = v1 match { - case SubqueryAlias(_, SubqueryAlias(identifier, _)) - if isPathIdentifier(identifier.name, spark) => - Seq(identifier.name).map(Uri) + case SubqueryAlias(_, SubqueryAlias(identifier, _)) => + if (isPathIdentifier(identifier.name, spark)) { + Seq(identifier.name).map(Uri) + } else { + Nil + } case SubqueryAlias(identifier, _) if isPathIdentifier(identifier.name, spark) => Seq(identifier.name).map(Uri) + case _ => Nil } } diff --git a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/DeltaCommands.scala b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/DeltaCommands.scala index 82627a0bf6d..db72cde83e5 100644 --- a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/DeltaCommands.scala +++ b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/DeltaCommands.scala @@ -41,13 +41,8 @@ object DeltaCommands extends CommandSpecs[TableCommandSpec] { val MergeIntoCommand = { val cmd = "org.apache.spark.sql.delta.commands.MergeIntoCommand" - val actionTypeDesc = ActionTypeDesc(actionType = Some(UPDATE)) - val tableDesc = TableDesc( - "target", - classOf[SubqueryAliasTableExtractor], - actionTypeDesc = Some(actionTypeDesc)) val queryDesc = QueryDesc("source") - TableCommandSpec(cmd, Seq(tableDesc), queryDescs = Seq(queryDesc)) + DeleteCommand.copy(classname = cmd, queryDescs = Seq(queryDesc)) } val OptimizeTableCommand = { diff --git a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/DeltaCatalogRangerSparkExtensionSuite.scala b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/DeltaCatalogRangerSparkExtensionSuite.scala index 331bd380df0..801f9f7458c 100644 --- a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/DeltaCatalogRangerSparkExtensionSuite.scala +++ b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/DeltaCatalogRangerSparkExtensionSuite.scala @@ -387,6 +387,51 @@ class DeltaCatalogRangerSparkExtensionSuite extends RangerSparkExtensionSuite { } } } + + test("merge into path-based table") { + withSingleCallEnabled { + withCleanTmpResources(Seq( + (s"$namespace1.$table2", "table"), + (s"$namespace1", "database"))) { + doAs(admin, sql(s"CREATE DATABASE IF NOT EXISTS $namespace1")) + doAs(admin, sql(createTableSql(namespace1, table2))) + withTempDir(path => { + doAs(admin, sql(createPathBasedTableSql(path))) + val mergeIntoSql = + s""" + |MERGE INTO delta.`$path` AS target + |USING $namespace1.$table2 AS source + |ON target.id = source.id + |WHEN MATCHED THEN + | UPDATE SET + | id = source.id, + | name = source.name, + | gender = source.gender, + | birthDate = source.birthDate + |WHEN NOT MATCHED + | THEN INSERT ( + | id, + | name, + | gender, + | birthDate + | ) + | VALUES ( + | source.id, + | source.name, + | source.gender, + | source.birthDate + | ) + |""".stripMargin + interceptContains[AccessControlException]( + doAs(someone, sql(mergeIntoSql)))( + s"does not have [select] privilege on [$namespace1/$table2/id," + + s"$namespace1/$table2/name,$namespace1/$table2/gender," + + s"$namespace1/$table2/birthDate], [write] privilege on [[$path, $path/]]") + doAs(admin, sql(mergeIntoSql)) + }) + } + } + } } object DeltaCatalogRangerSparkExtensionSuite {