@@ -399,4 +399,102 @@ class AppendDataTransactionSuite extends RowLevelOperationSuiteBase {
399399 Row (1 , 100 , " hr" ),
400400 Row (2 , 200 , " software" )))
401401 }
402+
403+ test(" SQL INSERT WITH SCHEMA EVOLUTION adds new column with transactional checks" ) {
404+ createAndInitTable(" pk INT NOT NULL, salary INT, dep STRING" ,
405+ """ { "pk": 1, "salary": 100, "dep": "hr" }
406+ |{ "pk": 2, "salary": 200, "dep": "software" }
407+ |""" .stripMargin)
408+
409+ sql(
410+ s """ CREATE TABLE $sourceNameAsString
411+ |(pk INT NOT NULL, salary INT, dep STRING, active BOOLEAN) """ .stripMargin)
412+ sql(s " INSERT INTO $sourceNameAsString VALUES (3, 300, 'hr', true), (4, 400, 'software', false) " )
413+
414+ val (txn, txnTables) = executeTransaction {
415+ sql(s " INSERT WITH SCHEMA EVOLUTION INTO $tableNameAsString SELECT * FROM $sourceNameAsString" )
416+ }
417+
418+ assert(txn.currentState === Committed )
419+ assert(txn.isClosed)
420+
421+ // the new column must be visible in the committed delegate's schema
422+ assert(table.schema.fieldNames.toSeq === Seq (" pk" , " salary" , " dep" , " active" ))
423+
424+ checkAnswer(
425+ sql(s " SELECT * FROM $tableNameAsString" ),
426+ Seq (
427+ Row (1 , 100 , " hr" , null ), // pre-existing rows: active is null
428+ Row (2 , 200 , " software" , null ),
429+ Row (3 , 300 , " hr" , true ), // inserted with active
430+ Row (4 , 400 , " software" , false )))
431+ }
432+
433+ for (isDynamic <- Seq (false , true ))
434+ test(s " SQL INSERT OVERWRITE WITH SCHEMA EVOLUTION adds new column with transactional checks " +
435+ s " isDynamic: $isDynamic" ) {
436+ createAndInitTable(" pk INT NOT NULL, salary INT, dep STRING" ,
437+ """ { "pk": 1, "salary": 100, "dep": "hr" }
438+ |{ "pk": 2, "salary": 200, "dep": "software" }
439+ |{ "pk": 3, "salary": 300, "dep": "hr" }
440+ |""" .stripMargin)
441+
442+ sql(
443+ s """ CREATE TABLE $sourceNameAsString
444+ |(pk INT NOT NULL, salary INT, dep STRING, active BOOLEAN) """ .stripMargin)
445+ sql(s " INSERT INTO $sourceNameAsString VALUES (11, 999, 'hr', true), (12, 888, 'hr', false) " )
446+
447+ val insertOverwrite = if (isDynamic) {
448+ s """ INSERT WITH SCHEMA EVOLUTION OVERWRITE TABLE $tableNameAsString
449+ |SELECT * FROM $sourceNameAsString
450+ | """ .stripMargin
451+ } else {
452+ s """ INSERT WITH SCHEMA EVOLUTION OVERWRITE TABLE $tableNameAsString
453+ |PARTITION (dep = 'hr')
454+ |SELECT pk, salary, active FROM $sourceNameAsString
455+ | """ .stripMargin
456+ }
457+
458+ val confValue = if (isDynamic) PartitionOverwriteMode .DYNAMIC else PartitionOverwriteMode .STATIC
459+ val (txn, _) = withSQLConf(SQLConf .PARTITION_OVERWRITE_MODE .key -> confValue.toString) {
460+ executeTransaction { sql(insertOverwrite) }
461+ }
462+
463+ assert(txn.currentState === Committed )
464+ assert(txn.isClosed)
465+
466+ // the new column must be visible in the committed delegate's schema
467+ assert(table.schema.fieldNames.contains(" active" ))
468+
469+ checkAnswer(
470+ sql(s " SELECT * FROM $tableNameAsString" ),
471+ Seq (
472+ Row (2 , 200 , " software" , null ), // unchanged (different partition)
473+ Row (11 , 999 , " hr" , true ), // overwrote hr partition
474+ Row (12 , 888 , " hr" , false )))
475+ }
476+
477+ test(" SQL INSERT WITH SCHEMA EVOLUTION analysis failure aborts transaction" ) {
478+ createAndInitTable(" pk INT NOT NULL, salary INT, dep STRING" ,
479+ """ { "pk": 1, "salary": 100, "dep": "hr" }
480+ |{ "pk": 2, "salary": 200, "dep": "software" }
481+ |""" .stripMargin)
482+
483+ sql(
484+ s """ CREATE TABLE $sourceNameAsString
485+ |(pk INT NOT NULL, salary INT, dep STRING, active BOOLEAN) """ .stripMargin)
486+
487+ val e = intercept[AnalysisException ] {
488+ sql(
489+ s """ INSERT WITH SCHEMA EVOLUTION INTO $tableNameAsString
490+ |SELECT nonexistent_col FROM $sourceNameAsString
491+ | """ .stripMargin)
492+ }
493+
494+ assert(e.getMessage.contains(" nonexistent_col" ))
495+ assert(catalog.lastTransaction.currentState === Aborted )
496+ assert(catalog.lastTransaction.isClosed)
497+ // schema must be unchanged after the aborted transaction
498+ assert(table.schema.fieldNames.toSeq === Seq (" pk" , " salary" , " dep" ))
499+ }
402500}
0 commit comments