@@ -97,45 +97,63 @@ case class InsertIntoHadoopFsRelationCommand(
9797 outputPath = outputPath.toString,
9898 isAppend = isAppend)
9999
100- if (mode == SaveMode .Overwrite ) {
101- deleteMatchingPartitions(fs, qualifiedOutputPath, customPartitionLocations, committer)
100+ val doInsertion = (mode, pathExists) match {
101+ case (SaveMode .ErrorIfExists , true ) =>
102+ throw new AnalysisException (s " path $qualifiedOutputPath already exists. " )
103+ case (SaveMode .Overwrite , true ) =>
104+ deleteMatchingPartitions(fs, qualifiedOutputPath, customPartitionLocations, committer)
105+ true
106+ case (SaveMode .Append , _) | (SaveMode .Overwrite , _) | (SaveMode .ErrorIfExists , false ) =>
107+ true
108+ case (SaveMode .Ignore , exists) =>
109+ ! exists
110+ case (s, exists) =>
111+ throw new IllegalStateException (s " unsupported save mode $s ( $exists) " )
102112 }
103113
104- // Callback for updating metastore partition metadata after the insertion job completes.
105- def refreshPartitionsCallback (updatedPartitions : Seq [TablePartitionSpec ]): Unit = {
106- if (partitionsTrackedByCatalog) {
107- val newPartitions = updatedPartitions.toSet -- initialMatchingPartitions
108- if (newPartitions.nonEmpty) {
109- AlterTableAddPartitionCommand (
110- catalogTable.get.identifier, newPartitions.toSeq.map(p => (p, None )),
111- ifNotExists = true ).run(sparkSession)
112- }
113- if (mode == SaveMode .Overwrite ) {
114- val deletedPartitions = initialMatchingPartitions.toSet -- updatedPartitions
115- if (deletedPartitions.nonEmpty) {
116- AlterTableDropPartitionCommand (
117- catalogTable.get.identifier, deletedPartitions.toSeq,
118- ifExists = true , purge = false ,
119- retainData = true /* already deleted */ ).run(sparkSession)
114+ if (doInsertion) {
115+
116+ // Callback for updating metastore partition metadata after the insertion job completes.
117+ def refreshPartitionsCallback (updatedPartitions : Seq [TablePartitionSpec ]): Unit = {
118+ if (partitionsTrackedByCatalog) {
119+ val newPartitions = updatedPartitions.toSet -- initialMatchingPartitions
120+ if (newPartitions.nonEmpty) {
121+ AlterTableAddPartitionCommand (
122+ catalogTable.get.identifier, newPartitions.toSeq.map(p => (p, None )),
123+ ifNotExists = true ).run(sparkSession)
124+ }
125+ if (mode == SaveMode .Overwrite ) {
126+ val deletedPartitions = initialMatchingPartitions.toSet -- updatedPartitions
127+ if (deletedPartitions.nonEmpty) {
128+ AlterTableDropPartitionCommand (
129+ catalogTable.get.identifier, deletedPartitions.toSeq,
130+ ifExists = true , purge = false ,
131+ retainData = true /* already deleted */ ).run(sparkSession)
132+ }
120133 }
121134 }
122135 }
123- }
124136
125- FileFormatWriter .write(
126- sparkSession = sparkSession,
127- queryExecution = Dataset .ofRows(sparkSession, query).queryExecution,
128- fileFormat = fileFormat,
129- committer = committer,
130- outputSpec = FileFormatWriter .OutputSpec (
131- qualifiedOutputPath.toString, customPartitionLocations),
132- hadoopConf = hadoopConf,
133- partitionColumns = partitionColumns,
134- bucketSpec = bucketSpec,
135- refreshFunction = refreshPartitionsCallback,
136- options = options)
137-
138- fileIndex.foreach(_.refresh())
137+ FileFormatWriter .write(
138+ sparkSession = sparkSession,
139+ queryExecution = Dataset .ofRows(sparkSession, query).queryExecution,
140+ fileFormat = fileFormat,
141+ committer = committer,
142+ outputSpec = FileFormatWriter .OutputSpec (
143+ qualifiedOutputPath.toString, customPartitionLocations),
144+ hadoopConf = hadoopConf,
145+ partitionColumns = partitionColumns,
146+ bucketSpec = bucketSpec,
147+ refreshFunction = refreshPartitionsCallback,
148+ options = options)
149+
150+ // refresh cached files in FileIndex
151+ fileIndex.foreach(_.refresh())
152+ // refresh data cache if table is cached
153+ sparkSession.catalog.refreshByPath(outputPath.toString)
154+ } else {
155+ logInfo(" Skipping insertion into a relation that already exists." )
156+ }
139157
140158 Seq .empty[Row ]
141159 }
0 commit comments