Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ query
insertInto
: INSERT OVERWRITE TABLE? identifierReference optionsClause? (partitionSpec (IF errorCapturingNot EXISTS)?)? ((BY NAME) | identifierList)? #insertOverwriteTable
| INSERT INTO TABLE? identifierReference optionsClause? partitionSpec? (IF errorCapturingNot EXISTS)? ((BY NAME) | identifierList)? #insertIntoTable
| INSERT INTO TABLE? identifierReference optionsClause? REPLACE whereClause #insertIntoReplaceWhere
| INSERT INTO TABLE? identifierReference optionsClause? (BY NAME)? REPLACE whereClause #insertIntoReplaceWhere
| INSERT OVERWRITE LOCAL? DIRECTORY path=stringLit rowFormat? createFileFormat? #insertOverwriteHiveDir
| INSERT OVERWRITE LOCAL? DIRECTORY (path=stringLit)? tableProvider (OPTIONS options=propertyList)? #insertOverwriteDir
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -928,11 +928,15 @@ class AstBuilder extends DataTypeAstBuilder
case ctx: InsertIntoReplaceWhereContext =>
val options = Option(ctx.optionsClause())
withIdentClause(ctx.identifierReference, Seq(query), (ident, otherPlans) => {
OverwriteByExpression.byPosition(
createUnresolvedRelation(ctx.identifierReference, ident, options,
Seq(TableWritePrivilege.INSERT, TableWritePrivilege.DELETE), isStreaming = false),
otherPlans.head,
expression(ctx.whereClause().booleanExpression()))
val table = createUnresolvedRelation(ctx.identifierReference, ident, options,
Seq(TableWritePrivilege.INSERT, TableWritePrivilege.DELETE), isStreaming = false)
val deleteExpr = expression(ctx.whereClause().booleanExpression())
val isByName = ctx.NAME() != null
if (isByName) {
OverwriteByExpression.byName(table, otherPlans.head, deleteExpr)
} else {
OverwriteByExpression.byPosition(table, otherPlans.head, deleteExpr)
}
})
case dir: InsertOverwriteDirContext =>
val (isLocal, storage, provider) = visitInsertOverwriteDir(dir)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ class DDLParserSuite extends AnalysisTest {
case u: UnresolvedRelation => i.copy(table = u.clearWritePrivileges)
case _ => i
}
case o: OverwriteByExpression =>
o.table match {
case u: UnresolvedRelation => o.copy(table = u.clearWritePrivileges)
case _ => o
}
}
comparePlans(parsed, expected, checkAnalysis = false)
}
Expand Down Expand Up @@ -1763,6 +1768,28 @@ class DDLParserSuite extends AnalysisTest {
)
}

test("insert table: REPLACE WHERE with BY NAME") {
parseCompare(
"INSERT INTO testcat.ns1.ns2.tbl BY NAME REPLACE WHERE a > 5 SELECT * FROM source",
OverwriteByExpression.byName(
UnresolvedRelation(Seq("testcat", "ns1", "ns2", "tbl")),
Project(Seq(UnresolvedStar(None)), UnresolvedRelation(Seq("source"))),
org.apache.spark.sql.catalyst.expressions.GreaterThan(
UnresolvedAttribute("a"),
Literal(5))))
}

test("insert table: REPLACE WHERE without BY NAME") {
parseCompare(
"INSERT INTO testcat.ns1.ns2.tbl REPLACE WHERE a > 5 SELECT * FROM source",
OverwriteByExpression.byPosition(
UnresolvedRelation(Seq("testcat", "ns1", "ns2", "tbl")),
Project(Seq(UnresolvedStar(None)), UnresolvedRelation(Seq("source"))),
org.apache.spark.sql.catalyst.expressions.GreaterThan(
UnresolvedAttribute("a"),
Literal(5))))
}

test("delete from table: delete all") {
parseCompare("DELETE FROM testcat.ns1.ns2.tbl",
DeleteFromTable(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3534,6 +3534,106 @@ class DataSourceV2SQLSuiteV1Filter
}
}

test("Selective Overwrite: REPLACE WHERE with BY NAME - column reordering") {
val df = spark.createDataFrame(Seq((1L, "a"), (2L, "b"), (3L, "c"))).toDF("id", "data")
df.createOrReplaceTempView("source")
val df2 = spark.createDataFrame(Seq(("d", 4L), ("e", 5L), ("f", 6L))).toDF("data", "id")
df2.createOrReplaceTempView("source2_reordered")

val t = "testcat.tbl"
withTable(t) {
spark.sql(
s"CREATE TABLE $t (id bigint, data string) USING foo PARTITIONED BY (id)")
spark.sql(s"INSERT INTO TABLE $t SELECT * FROM source")

checkAnswer(
spark.table(s"$t"),
Seq(Row(1L, "a"), Row(2L, "b"), Row(3L, "c")))

spark.sql(s"INSERT INTO $t BY NAME REPLACE WHERE id = 3 SELECT * FROM source2_reordered")
checkAnswer(
spark.table(s"$t"),
Seq(Row(1L, "a"), Row(2L, "b"), Row(4L, "d"), Row(5L, "e"), Row(6L, "f")))
}
}

test("Overwrite: REPLACE WHERE without BY NAME - positional matching") {
val df = spark.createDataFrame(Seq((1L, "a"), (2L, "b"), (3L, "c"))).toDF("id", "data")
df.createOrReplaceTempView("source")
val df2 = spark.createDataFrame(Seq((4L, "d"), (5L, "e"), (6L, "f"))).toDF("data", "id")
df2.createOrReplaceTempView("source2_names_reordered")

val t = "testcat.tbl"
withTable(t) {
spark.sql(
s"CREATE TABLE $t (id bigint, data string) USING foo PARTITIONED BY (id)")
spark.sql(s"INSERT INTO TABLE $t SELECT * FROM source")

checkAnswer(
spark.table(s"$t"),
Seq(Row(1L, "a"), Row(2L, "b"), Row(3L, "c")))

spark.sql(s"INSERT INTO $t REPLACE WHERE id = 3 SELECT * FROM source2_names_reordered")
checkAnswer(
spark.table(s"$t"),
Seq(Row(1L, "a"), Row(2L, "b"), Row(4L, "d"), Row(5L, "e"), Row(6L, "f")))
}
}

test("Overwrite: REPLACE WHERE without BY NAME - different column order between 2 tables, " +
"compatible types") {
val df = spark.createDataFrame(Seq((1L, 11L), (2L, 12L), (3L, 13L))).toDF("id", "data")
df.createOrReplaceTempView("source")
val df2 = spark.createDataFrame(Seq((14L, 4L), (15L, 5L), (16L, 6L))).toDF("data", "id")
df2.createOrReplaceTempView("source2_reordered")

val t = "testcat.tbl"
withTable(t) {
spark.sql(
s"CREATE TABLE $t (id bigint, data bigint) USING foo PARTITIONED BY (id)")
spark.sql(s"INSERT INTO TABLE $t SELECT * FROM source")

checkAnswer(
spark.table(s"$t"),
Seq(Row(1L, 11L), Row(2L, 12L), Row(3L, 13L)))

spark.sql(s"INSERT INTO $t REPLACE WHERE id = 3 SELECT * FROM source2_reordered")
checkAnswer(
spark.table(s"$t"),
Seq(Row(1L, 11L), Row(2L, 12L), Row(14L, 4L), Row(15L, 5L), Row(16L, 6L)))
}
}

test("Overwrite: REPLACE WHERE without BY NAME - incompatible types") {
val df = spark.createDataFrame(Seq((1L, "a"), (2L, "b"), (3L, "c"))).toDF("id", "data")
df.createOrReplaceTempView("source")
val df2 = spark.createDataFrame(Seq(("d", 4L), ("e", 5L), ("f", 6L))).toDF("data", "id")
df2.createOrReplaceTempView("source2_reordered")

val t = "testcat.tbl"
withTable(t) {
spark.sql(
s"CREATE TABLE $t (id bigint, data string) USING foo PARTITIONED BY (id)")
spark.sql(s"INSERT INTO TABLE $t SELECT * FROM source")

checkAnswer(
spark.table(s"$t"),
Seq(Row(1L, "a"), Row(2L, "b"), Row(3L, "c")))

checkError(
exception = intercept[AnalysisException] {
spark.sql(s"INSERT INTO $t REPLACE WHERE id = 3 SELECT * FROM source2_reordered")
},
condition = "INCOMPATIBLE_DATA_FOR_TABLE.CANNOT_SAFELY_CAST",
parameters = Map(
"tableName" -> "`testcat`.`tbl`",
"colName" -> "`id`",
"srcType" -> "\"STRING\"",
"targetType" -> "\"BIGINT\"")
)
}
}

test("SPARK-46144: Fail overwrite statement if the condition contains subquery") {
val df = spark.createDataFrame(Seq((1L, "a"), (2L, "b"), (3L, "c"))).toDF("id", "data")
df.createOrReplaceTempView("source")
Expand Down