@@ -22,27 +22,31 @@ import io.substrait.spark.expression._
2222import org .apache .spark .internal .Logging
2323import org .apache .spark .sql .SaveMode
2424import org .apache .spark .sql .catalyst .InternalRow
25+ import org .apache .spark .sql .catalyst .analysis .ResolvedIdentifier
2526import org .apache .spark .sql .catalyst .catalog .{CatalogTable , HiveTableRelation }
2627import org .apache .spark .sql .catalyst .expressions ._
2728import org .apache .spark .sql .catalyst .expressions .aggregate .{AggregateExpression , Average , Sum }
2829import org .apache .spark .sql .catalyst .plans ._
2930import org .apache .spark .sql .catalyst .plans .logical ._
3031import org .apache .spark .sql .execution .LogicalRDD
31- import org .apache .spark .sql .execution .command .CreateDataSourceTableAsSelectCommand
32+ import org .apache .spark .sql .execution .command .{ CreateDataSourceTableAsSelectCommand , CreateTableCommand , DropTableCommand }
3233import org .apache .spark .sql .execution .datasources .{FileFormat => DSFileFormat , HadoopFsRelation , InsertIntoHadoopFsRelationCommand , LogicalRelation , V1WriteCommand , WriteFiles }
3334import org .apache .spark .sql .execution .datasources .csv .CSVFileFormat
3435import org .apache .spark .sql .execution .datasources .orc .OrcFileFormat
3536import org .apache .spark .sql .execution .datasources .parquet .ParquetFileFormat
36- import org .apache .spark .sql .execution .datasources .v2 .{DataSourceV2Relation , DataSourceV2ScanRelation }
37+ import org .apache .spark .sql .execution .datasources .v2 .{DataSourceV2Relation , DataSourceV2ScanRelation , V2SessionCatalog }
38+ import org .apache .spark .sql .hive .execution .{CreateHiveTableAsSelectCommand , InsertIntoHiveTable }
3739import org .apache .spark .sql .types .{NullType , StructType }
3840
3941import io .substrait .`type` .{NamedStruct , Type }
4042import io .substrait .{proto , relation }
4143import io .substrait .debug .TreePrinter
4244import io .substrait .expression .{Expression => SExpression , ExpressionCreator }
45+ import io .substrait .expression .Expression .StructLiteral
4346import io .substrait .extension .ExtensionCollector
4447import io .substrait .hint .Hint
4548import io .substrait .plan .Plan
49+ import io .substrait .relation .AbstractDdlRel .{DdlObject , DdlOp }
4650import io .substrait .relation .AbstractWriteRel .{CreateMode , OutputMode , WriteOp }
4751import io .substrait .relation .RelProtoConverter
4852import io .substrait .relation .Set .SetOp
@@ -54,7 +58,7 @@ import io.substrait.utils.Util
5458import java .util
5559import java .util .{Collections , Optional }
5660
57- import scala .collection .JavaConverters .asJavaIterableConverter
61+ import scala .collection .JavaConverters .{ asJavaIterableConverter , seqAsJavaList }
5862import scala .collection .mutable
5963import scala .collection .mutable .ArrayBuffer
6064
@@ -75,9 +79,7 @@ class ToSubstraitRel extends AbstractLogicalPlanVisitor with Logging {
7579 override def default (p : LogicalPlan ): relation.Rel = p match {
7680 case c : CommandResult => visit(c.commandLogicalPlan)
7781 case w : WriteFiles => visit(w.child)
78- case c : V1WriteCommand => convertDataWritingCommand(c)
79- case CreateDataSourceTableAsSelectCommand (table, mode, query, names) =>
80- convertCTAS(table, mode, query, names)
82+ case c : Command => convertCommand(c)
8183 case p : LeafNode => convertReadOperator(p)
8284 case s : SubqueryAlias => visit(s.child)
8385 case v : View => visit(v.child)
@@ -566,6 +568,28 @@ class ToSubstraitRel extends AbstractLogicalPlanVisitor with Logging {
566568 }
567569 }
568570
571+ private def convertCommand (command : Command ): relation.Rel = command match {
572+ case c : V1WriteCommand => convertDataWritingCommand(c)
573+ case CreateDataSourceTableAsSelectCommand (table, mode, query, names) =>
574+ convertCTAS(table, mode, query, names)
575+ case CreateHiveTableAsSelectCommand (table, query, names, mode) =>
576+ convertCTAS(table, mode, query, names)
577+ case CreateTableCommand (table, _) =>
578+ convertCreateTable(table.identifier.unquotedString.split(" \\ ." ), table.schema)
579+ case DropTableCommand (tableName, ifExists, _, _) =>
580+ convertDropTable(tableName.unquotedString.split(" \\ ." ), ifExists)
581+ case CreateTable (ResolvedIdentifier (c : V2SessionCatalog , id), tableSchema, _, _, _)
582+ if id.namespace().length > 0 =>
583+ val names = Seq (c.name(), id.namespace()(0 ), id.name())
584+ convertCreateTable(names, tableSchema)
585+ case DropTable (ResolvedIdentifier (c : V2SessionCatalog , id), ifExists, _)
586+ if id.namespace().length > 0 =>
587+ val names = Seq (c.name(), id.namespace()(0 ), id.name())
588+ convertDropTable(names, ifExists)
589+ case _ =>
590+ throw new UnsupportedOperationException (s " Unable to convert command: $command" )
591+ }
592+
569593 private def convertDataWritingCommand (command : V1WriteCommand ): relation.AbstractWriteRel =
570594 command match {
571595 case InsertIntoHadoopFsRelationCommand (
@@ -600,6 +624,16 @@ class ToSubstraitRel extends AbstractLogicalPlanVisitor with Logging {
600624 .tableSchema(outputSchema(child.output, outputColumnNames))
601625 .detail(FileHolder (file))
602626 .build()
627+ case InsertIntoHiveTable (table, _, child, overwrite, _, outputColumnNames, _, _, _, _, _) =>
628+ relation.NamedWrite
629+ .builder()
630+ .input(visit(child))
631+ .operation(WriteOp .INSERT )
632+ .outputMode(OutputMode .UNSPECIFIED )
633+ .createMode(if (overwrite) CreateMode .REPLACE_IF_EXISTS else CreateMode .ERROR_IF_EXISTS )
634+ .names(seqAsJavaList(table.identifier.unquotedString.split(" \\ ." ).toList))
635+ .tableSchema(outputSchema(child.output, outputColumnNames))
636+ .build()
603637 case _ =>
604638 throw new UnsupportedOperationException (s " Unable to convert command: ${command.getClass}" )
605639 }
@@ -619,6 +653,29 @@ class ToSubstraitRel extends AbstractLogicalPlanVisitor with Logging {
619653 .tableSchema(outputSchema(query.output, outputColumnNames))
620654 .build()
621655
656+ private def convertCreateTable (names : Seq [String ], schema : StructType ): relation.NamedDdl = {
657+ relation.NamedDdl
658+ .builder()
659+ .operation(DdlOp .CREATE )
660+ .`object`(DdlObject .TABLE )
661+ .names(seqAsJavaList(names))
662+ .tableSchema(ToSubstraitType .toNamedStruct(schema))
663+ .tableDefaults(StructLiteral .builder.nullable(true ).build())
664+ .build()
665+ }
666+
667+ private def convertDropTable (names : Seq [String ], ifExists : Boolean ): relation.NamedDdl = {
668+ relation.NamedDdl
669+ .builder()
670+ .operation(if (ifExists) DdlOp .DROP_IF_EXIST else DdlOp .DROP )
671+ .`object`(DdlObject .TABLE )
672+ .names(seqAsJavaList(names))
673+ .tableSchema(
674+ NamedStruct .builder().struct(Type .Struct .builder().nullable(true ).build()).build())
675+ .tableDefaults(StructLiteral .builder.nullable(true ).build())
676+ .build()
677+ }
678+
622679 private def createMode (mode : SaveMode ): CreateMode = mode match {
623680 case SaveMode .Append => CreateMode .APPEND_IF_EXISTS
624681 case SaveMode .Overwrite => CreateMode .REPLACE_IF_EXISTS
0 commit comments