aboutsummaryrefslogtreecommitdiff
path: root/sql/hive/src/test
diff options
context:
space:
mode:
authorEric Liang <ekl@databricks.com>2016-12-01 16:48:10 +0800
committerWenchen Fan <wenchen@databricks.com>2016-12-01 16:48:10 +0800
commit88f559f20a5208f2386b874eb119f1cba2c748c7 (patch)
treeb416b8bb4a8881d964be2d0896d1ac4e20c71e8d /sql/hive/src/test
parentb28fe4a4a9d93375a7aa0987ebb1cdaf4b8fcf5d (diff)
downloadspark-88f559f20a5208f2386b874eb119f1cba2c748c7.tar.gz
spark-88f559f20a5208f2386b874eb119f1cba2c748c7.tar.bz2
spark-88f559f20a5208f2386b874eb119f1cba2c748c7.zip
[SPARK-18635][SQL] Partition name/values not escaped correctly in some cases
## What changes were proposed in this pull request? Due to confusion between URI vs paths, in certain cases we escape partition values too many times, which causes some Hive client operations to fail or write data to the wrong location. This PR fixes at least some of these cases. To my understanding this is how values, filesystem paths, and URIs interact. - Hive stores raw (unescaped) partition values that are returned to you directly when you call listPartitions. - Internally, we convert these raw values to filesystem paths via `ExternalCatalogUtils.[un]escapePathName`. - In some circumstances we store URIs instead of filesystem paths. When a path is converted to a URI via `path.toURI`, the escaped partition values are further URI-encoded. This means that to get a path back from a URI, you must call `new Path(new URI(uriTxt))` in order to decode the URI-encoded string. - In `CatalogStorageFormat` we store URIs as strings. This makes it easy to forget to URI-decode the value before converting it into a path. - Finally, the Hive client itself uses mostly Paths for representing locations, and only URIs occasionally. In the future we should probably clean this up, perhaps by dropping use of URIs when unnecessary. We should also try fixing escaping for partition names as well as values, though names are unlikely to contain special characters. cc mallman cloud-fan yhuai ## How was this patch tested? Unit tests. Author: Eric Liang <ekl@databricks.com> Closes #16071 from ericl/spark-18635.
Diffstat (limited to 'sql/hive/src/test')
-rw-r--r--sql/hive/src/test/scala/org/apache/spark/sql/hive/PartitionProviderCompatibilitySuite.scala54
1 files changed, 54 insertions, 0 deletions
diff --git a/sql/hive/src/test/scala/org/apache/spark/sql/hive/PartitionProviderCompatibilitySuite.scala b/sql/hive/src/test/scala/org/apache/spark/sql/hive/PartitionProviderCompatibilitySuite.scala
index cace5fa95c..e8e4238d1c 100644
--- a/sql/hive/src/test/scala/org/apache/spark/sql/hive/PartitionProviderCompatibilitySuite.scala
+++ b/sql/hive/src/test/scala/org/apache/spark/sql/hive/PartitionProviderCompatibilitySuite.scala
@@ -205,6 +205,60 @@ class PartitionProviderCompatibilitySuite
}
}
}
+
+ test(s"SPARK-18635 special chars in partition values - partition management $enabled") {
+ withTable("test") {
+ spark.range(10)
+ .selectExpr("id", "id as A", "'%' as B")
+ .write.partitionBy("A", "B").mode("overwrite")
+ .saveAsTable("test")
+ assert(spark.sql("select * from test").count() == 10)
+ assert(spark.sql("select * from test where B = '%'").count() == 10)
+ assert(spark.sql("select * from test where B = '$'").count() == 0)
+ spark.range(10)
+ .selectExpr("id", "id as A", "'=' as B")
+ .write.mode("append").insertInto("test")
+ spark.sql("insert into test partition (A, B) select id, id, '%=' from range(10)")
+ assert(spark.sql("select * from test").count() == 30)
+ assert(spark.sql("select * from test where B = '%'").count() == 10)
+ assert(spark.sql("select * from test where B = '='").count() == 10)
+ assert(spark.sql("select * from test where B = '%='").count() == 10)
+
+ // show partitions sanity check
+ val parts = spark.sql("show partitions test").collect().map(_.get(0)).toSeq
+ assert(parts.length == 30)
+ assert(parts.contains("A=0/B=%25"))
+ assert(parts.contains("A=0/B=%3D"))
+ assert(parts.contains("A=0/B=%25%3D"))
+
+ // drop partition sanity check
+ spark.sql("alter table test drop partition (A=1, B='%')")
+ assert(spark.sql("select * from test").count() == 29) // 1 file in dropped partition
+
+ withTempDir { dir =>
+ // custom locations sanity check
+ spark.sql(s"""
+ |alter table test partition (A=0, B='%')
+ |set location '${dir.getAbsolutePath}'""".stripMargin)
+ assert(spark.sql("select * from test").count() == 28) // moved to empty dir
+
+ // rename partition sanity check
+ spark.sql(s"""
+ |alter table test partition (A=5, B='%')
+ |rename to partition (A=100, B='%')""".stripMargin)
+ assert(spark.sql("select * from test where a = 5 and b = '%'").count() == 0)
+ assert(spark.sql("select * from test where a = 100 and b = '%'").count() == 1)
+
+ // try with A=0 which has a custom location
+ spark.sql("insert into test partition (A=0, B='%') select 1")
+ spark.sql(s"""
+ |alter table test partition (A=0, B='%')
+ |rename to partition (A=101, B='%')""".stripMargin)
+ assert(spark.sql("select * from test where a = 0 and b = '%'").count() == 0)
+ assert(spark.sql("select * from test where a = 101 and b = '%'").count() == 1)
+ }
+ }
+ }
}
/**