From a19219799003c07d37064981f6fb2e15505968c8 Mon Sep 17 00:00:00 2001 From: Jovan Pavlovic Date: Thu, 3 Oct 2024 12:06:47 +0200 Subject: [PATCH 1/9] block trim collation. --- .../sql/internal/types/AbstractStringType.scala | 16 +++++++++++----- .../org/apache/spark/sql/types/StringType.scala | 3 +++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala index 6feb662632763..1911e95e62629 100644 --- a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala +++ b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala @@ -23,9 +23,12 @@ import org.apache.spark.sql.types.{AbstractDataType, DataType, StringType} /** * AbstractStringType is an abstract class for StringType with collation support. */ -abstract class AbstractStringType extends AbstractDataType { +abstract class AbstractStringType( + private[sql] val supportsTrimCollation: Boolean = false) extends AbstractDataType { override private[sql] def defaultConcreteType: DataType = SqlApiConf.get.defaultStringType override private[sql] def simpleString: String = "string" + private[sql] def canUseTrimCollation(other: DataType): Boolean = + supportsTrimCollation && other.asInstanceOf[StringType].usesTrimCollation } /** @@ -33,7 +36,8 @@ abstract class AbstractStringType extends AbstractDataType { */ case object StringTypeBinary extends AbstractStringType { override private[sql] def acceptsType(other: DataType): Boolean = - other.isInstanceOf[StringType] && other.asInstanceOf[StringType].supportsBinaryEquality + other.isInstanceOf[StringType] && other.asInstanceOf[StringType].supportsBinaryEquality && + canUseTrimCollation(other) } /** @@ -42,7 +46,7 @@ case object StringTypeBinary extends AbstractStringType { case object StringTypeBinaryLcase extends AbstractStringType { override private[sql] def acceptsType(other: DataType): Boolean = other.isInstanceOf[StringType] && (other.asInstanceOf[StringType].supportsBinaryEquality || - other.asInstanceOf[StringType].isUTF8LcaseCollation) + other.asInstanceOf[StringType].isUTF8LcaseCollation) && canUseTrimCollation(other) } /** @@ -50,7 +54,8 @@ case object StringTypeBinaryLcase extends AbstractStringType { * and ICU) but limited to using case and accent sensitivity specifiers. */ case object StringTypeWithCaseAccentSensitivity extends AbstractStringType { - override private[sql] def acceptsType(other: DataType): Boolean = other.isInstanceOf[StringType] + override private[sql] def acceptsType(other: DataType): Boolean = + other.isInstanceOf[StringType] && canUseTrimCollation(other) } /** @@ -59,5 +64,6 @@ case object StringTypeWithCaseAccentSensitivity extends AbstractStringType { */ case object StringTypeNonCSAICollation extends AbstractStringType { override private[sql] def acceptsType(other: DataType): Boolean = - other.isInstanceOf[StringType] && other.asInstanceOf[StringType].isNonCSAI + other.isInstanceOf[StringType] && other.asInstanceOf[StringType].isNonCSAI && + canUseTrimCollation(other) } diff --git a/sql/api/src/main/scala/org/apache/spark/sql/types/StringType.scala b/sql/api/src/main/scala/org/apache/spark/sql/types/StringType.scala index c2dd6cec7ba74..29d48e3d1f47f 100644 --- a/sql/api/src/main/scala/org/apache/spark/sql/types/StringType.scala +++ b/sql/api/src/main/scala/org/apache/spark/sql/types/StringType.scala @@ -47,6 +47,9 @@ class StringType private (val collationId: Int) extends AtomicType with Serializ private[sql] def isNonCSAI: Boolean = !CollationFactory.isCaseSensitiveAndAccentInsensitive(collationId) + private[sql] def usesTrimCollation: Boolean = + CollationFactory.usesTrimCollation(collationId) + private[sql] def isUTF8BinaryCollation: Boolean = collationId == CollationFactory.UTF8_BINARY_COLLATION_ID From 3b60113de99513a6005dc80c2f81e8361730e76c Mon Sep 17 00:00:00 2001 From: Jovan Pavlovic Date: Thu, 3 Oct 2024 13:43:41 +0200 Subject: [PATCH 2/9] apply demorgan rule. --- .../apache/spark/sql/internal/types/AbstractStringType.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala index 1911e95e62629..01e2e38b56598 100644 --- a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala +++ b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala @@ -28,7 +28,7 @@ abstract class AbstractStringType( override private[sql] def defaultConcreteType: DataType = SqlApiConf.get.defaultStringType override private[sql] def simpleString: String = "string" private[sql] def canUseTrimCollation(other: DataType): Boolean = - supportsTrimCollation && other.asInstanceOf[StringType].usesTrimCollation + supportsTrimCollation || !other.asInstanceOf[StringType].usesTrimCollation } /** From a39f94ff8c0e5dee1743cd6f46ec427a0c20b9ae Mon Sep 17 00:00:00 2001 From: Jovan Pavlovic Date: Thu, 3 Oct 2024 14:19:13 +0200 Subject: [PATCH 3/9] fix formating. --- .../apache/spark/sql/internal/types/AbstractStringType.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala index 01e2e38b56598..e5a55f5e19d9c 100644 --- a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala +++ b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala @@ -23,8 +23,8 @@ import org.apache.spark.sql.types.{AbstractDataType, DataType, StringType} /** * AbstractStringType is an abstract class for StringType with collation support. */ -abstract class AbstractStringType( - private[sql] val supportsTrimCollation: Boolean = false) extends AbstractDataType { +abstract class AbstractStringType(private[sql] val supportsTrimCollation: Boolean = false) + extends AbstractDataType { override private[sql] def defaultConcreteType: DataType = SqlApiConf.get.defaultStringType override private[sql] def simpleString: String = "string" private[sql] def canUseTrimCollation(other: DataType): Boolean = From d4d70f150cdfa99b407bc10aa79d8d2f43432e1a Mon Sep 17 00:00:00 2001 From: Jovan Pavlovic Date: Thu, 3 Oct 2024 18:57:28 +0200 Subject: [PATCH 4/9] use companion object. --- .../internal/types/AbstractStringType.scala | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala index e5a55f5e19d9c..b8bca1ff381e5 100644 --- a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala +++ b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala @@ -34,36 +34,62 @@ abstract class AbstractStringType(private[sql] val supportsTrimCollation: Boolea /** * Use StringTypeBinary for expressions supporting only binary collation. */ -case object StringTypeBinary extends AbstractStringType { - override private[sql] def acceptsType(other: DataType): Boolean = - other.isInstanceOf[StringType] && other.asInstanceOf[StringType].supportsBinaryEquality && - canUseTrimCollation(other) -} +case class StringTypeBinary(override val supportsTrimCollation: Boolean = false) + extends AbstractStringType(supportsTrimCollation) { + override private[sql] def acceptsType(other: DataType): Boolean = + other.isInstanceOf[StringType] && other.asInstanceOf[StringType].supportsBinaryEquality && + canUseTrimCollation(other) + } +object StringTypeBinary extends StringTypeBinary(false) { + def apply(supportsTrimCollation: Boolean): StringTypeBinary = { + new StringTypeBinary(supportsTrimCollation) + } +} /** * Use StringTypeBinaryLcase for expressions supporting only binary and lowercase collation. */ -case object StringTypeBinaryLcase extends AbstractStringType { +case class StringTypeBinaryLcase(override val supportsTrimCollation: Boolean = false) + extends AbstractStringType(supportsTrimCollation) { override private[sql] def acceptsType(other: DataType): Boolean = other.isInstanceOf[StringType] && (other.asInstanceOf[StringType].supportsBinaryEquality || other.asInstanceOf[StringType].isUTF8LcaseCollation) && canUseTrimCollation(other) } +object StringTypeBinaryLcase extends StringTypeBinaryLcase(false) { + def apply(supportsTrimCollation: Boolean): StringTypeBinaryLcase = { + new StringTypeBinaryLcase(supportsTrimCollation) + } +} /** * Use StringTypeWithCaseAccentSensitivity for expressions supporting all collation types (binary * and ICU) but limited to using case and accent sensitivity specifiers. */ -case object StringTypeWithCaseAccentSensitivity extends AbstractStringType { +case class StringTypeWithCaseAccentSensitivity(override val supportsTrimCollation: Boolean = false) + extends AbstractStringType(supportsTrimCollation) { override private[sql] def acceptsType(other: DataType): Boolean = other.isInstanceOf[StringType] && canUseTrimCollation(other) } +object StringTypeWithCaseAccentSensitivity extends StringTypeWithCaseAccentSensitivity(false) { + def apply(supportsTrimCollation: Boolean): StringTypeWithCaseAccentSensitivity = { + new StringTypeWithCaseAccentSensitivity(supportsTrimCollation) + } +} + /** * Use StringTypeNonCSAICollation for expressions supporting all possible collation types except * CS_AI collation types. */ -case object StringTypeNonCSAICollation extends AbstractStringType { +case class StringTypeNonCSAICollation (override val supportsTrimCollation: Boolean = false) + extends AbstractStringType(supportsTrimCollation) { override private[sql] def acceptsType(other: DataType): Boolean = other.isInstanceOf[StringType] && other.asInstanceOf[StringType].isNonCSAI && canUseTrimCollation(other) } + +object StringTypeNonCSAICollation extends StringTypeNonCSAICollation(false) { + def apply(supportsTrimCollation: Boolean): StringTypeNonCSAICollation = { + new StringTypeNonCSAICollation(supportsTrimCollation) + } +} \ No newline at end of file From 4ab445555c266ad04db2d08eeb98c7abad661aa4 Mon Sep 17 00:00:00 2001 From: Hyukjin Kwon Date: Fri, 4 Oct 2024 10:51:59 +0900 Subject: [PATCH 5/9] Update sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala --- .../apache/spark/sql/internal/types/AbstractStringType.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala index b8bca1ff381e5..e94416b3aaeb2 100644 --- a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala +++ b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala @@ -92,4 +92,4 @@ object StringTypeNonCSAICollation extends StringTypeNonCSAICollation(false) { def apply(supportsTrimCollation: Boolean): StringTypeNonCSAICollation = { new StringTypeNonCSAICollation(supportsTrimCollation) } -} \ No newline at end of file +} From d6a728d62a72e1791ad83361b96be01ef39a5b2a Mon Sep 17 00:00:00 2001 From: Jovan Pavlovic Date: Fri, 4 Oct 2024 11:44:53 +0200 Subject: [PATCH 6/9] scalafmt changes. --- .../internal/types/AbstractStringType.scala | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala index e94416b3aaeb2..294e123b90867 100644 --- a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala +++ b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala @@ -35,22 +35,23 @@ abstract class AbstractStringType(private[sql] val supportsTrimCollation: Boolea * Use StringTypeBinary for expressions supporting only binary collation. */ case class StringTypeBinary(override val supportsTrimCollation: Boolean = false) - extends AbstractStringType(supportsTrimCollation) { - override private[sql] def acceptsType(other: DataType): Boolean = - other.isInstanceOf[StringType] && other.asInstanceOf[StringType].supportsBinaryEquality && - canUseTrimCollation(other) - } + extends AbstractStringType(supportsTrimCollation) { + override private[sql] def acceptsType(other: DataType): Boolean = + other.isInstanceOf[StringType] && other.asInstanceOf[StringType].supportsBinaryEquality && + canUseTrimCollation(other) +} object StringTypeBinary extends StringTypeBinary(false) { def apply(supportsTrimCollation: Boolean): StringTypeBinary = { new StringTypeBinary(supportsTrimCollation) } } + /** * Use StringTypeBinaryLcase for expressions supporting only binary and lowercase collation. */ case class StringTypeBinaryLcase(override val supportsTrimCollation: Boolean = false) - extends AbstractStringType(supportsTrimCollation) { + extends AbstractStringType(supportsTrimCollation) { override private[sql] def acceptsType(other: DataType): Boolean = other.isInstanceOf[StringType] && (other.asInstanceOf[StringType].supportsBinaryEquality || other.asInstanceOf[StringType].isUTF8LcaseCollation) && canUseTrimCollation(other) @@ -61,12 +62,14 @@ object StringTypeBinaryLcase extends StringTypeBinaryLcase(false) { new StringTypeBinaryLcase(supportsTrimCollation) } } + /** * Use StringTypeWithCaseAccentSensitivity for expressions supporting all collation types (binary * and ICU) but limited to using case and accent sensitivity specifiers. */ -case class StringTypeWithCaseAccentSensitivity(override val supportsTrimCollation: Boolean = false) - extends AbstractStringType(supportsTrimCollation) { +case class StringTypeWithCaseAccentSensitivity( + override val supportsTrimCollation: Boolean = false) + extends AbstractStringType(supportsTrimCollation) { override private[sql] def acceptsType(other: DataType): Boolean = other.isInstanceOf[StringType] && canUseTrimCollation(other) } @@ -81,8 +84,8 @@ object StringTypeWithCaseAccentSensitivity extends StringTypeWithCaseAccentSensi * Use StringTypeNonCSAICollation for expressions supporting all possible collation types except * CS_AI collation types. */ -case class StringTypeNonCSAICollation (override val supportsTrimCollation: Boolean = false) - extends AbstractStringType(supportsTrimCollation) { +case class StringTypeNonCSAICollation(override val supportsTrimCollation: Boolean = false) + extends AbstractStringType(supportsTrimCollation) { override private[sql] def acceptsType(other: DataType): Boolean = other.isInstanceOf[StringType] && other.asInstanceOf[StringType].isNonCSAI && canUseTrimCollation(other) From e79100b5fddd226460e99a4bdf9fa425a108fccd Mon Sep 17 00:00:00 2001 From: Jovan Pavlovic Date: Fri, 4 Oct 2024 16:58:33 +0200 Subject: [PATCH 7/9] fix tests. --- .../spark/sql/internal/types/AbstractStringType.scala | 3 ++- .../spark/sql/catalyst/expressions/CollationKey.scala | 3 ++- .../expressions/aggregate/datasketchesAggregates.scala | 6 +++++- .../sql/catalyst/expressions/collationExpressions.scala | 6 ++++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala index 294e123b90867..c3643f4bd15be 100644 --- a/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala +++ b/sql/api/src/main/scala/org/apache/spark/sql/internal/types/AbstractStringType.scala @@ -21,7 +21,8 @@ import org.apache.spark.sql.internal.SqlApiConf import org.apache.spark.sql.types.{AbstractDataType, DataType, StringType} /** - * AbstractStringType is an abstract class for StringType with collation support. + * AbstractStringType is an abstract class for StringType with collation support. As every type of + * collation can support trim specifier this class is parametrized with it. */ abstract class AbstractStringType(private[sql] val supportsTrimCollation: Boolean = false) extends AbstractDataType { diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/CollationKey.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/CollationKey.scala index 28ec8482e5cdd..81bafda54135f 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/CollationKey.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/CollationKey.scala @@ -24,7 +24,8 @@ import org.apache.spark.sql.types._ import org.apache.spark.unsafe.types.UTF8String case class CollationKey(expr: Expression) extends UnaryExpression with ExpectsInputTypes { - override def inputTypes: Seq[AbstractDataType] = Seq(StringTypeWithCaseAccentSensitivity) + override def inputTypes: Seq[AbstractDataType] = + Seq(StringTypeWithCaseAccentSensitivity(/* supportsTrimCollation = */ true)) override def dataType: DataType = BinaryType final lazy val collationId: Int = expr.dataType match { diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/aggregate/datasketchesAggregates.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/aggregate/datasketchesAggregates.scala index 78bd02d5703cd..a6448051a3996 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/aggregate/datasketchesAggregates.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/aggregate/datasketchesAggregates.scala @@ -106,7 +106,11 @@ case class HllSketchAgg( override def inputTypes: Seq[AbstractDataType] = Seq( - TypeCollection(IntegerType, LongType, StringTypeWithCaseAccentSensitivity, BinaryType), + TypeCollection( + IntegerType, + LongType, + StringTypeWithCaseAccentSensitivity(/* supportsTrimCollation = */ true), + BinaryType), IntegerType) override def dataType: DataType = BinaryType diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collationExpressions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collationExpressions.scala index b67e66323bbbd..24d6e74ad2972 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collationExpressions.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collationExpressions.scala @@ -77,7 +77,8 @@ case class Collate(child: Expression, collationName: String) extends UnaryExpression with ExpectsInputTypes { private val collationId = CollationFactory.collationNameToId(collationName) override def dataType: DataType = StringType(collationId) - override def inputTypes: Seq[AbstractDataType] = Seq(StringTypeWithCaseAccentSensitivity) + override def inputTypes: Seq[AbstractDataType] = + Seq(StringTypeWithCaseAccentSensitivity(/* supportsTrimCollation = */ true)) override protected def withNewChildInternal( newChild: Expression): Expression = copy(newChild) @@ -115,5 +116,6 @@ case class Collation(child: Expression) val collationName = CollationFactory.fetchCollation(collationId).collationName Literal.create(collationName, SQLConf.get.defaultStringType) } - override def inputTypes: Seq[AbstractDataType] = Seq(StringTypeWithCaseAccentSensitivity) + override def inputTypes: Seq[AbstractDataType] = + Seq(StringTypeWithCaseAccentSensitivity(/* supportsBinaryEquality = */ true)) } From a8da26e4d03ac5a9262b40fbd87de04017af27c8 Mon Sep 17 00:00:00 2001 From: Jovan Pavlovic Date: Fri, 4 Oct 2024 17:03:14 +0200 Subject: [PATCH 8/9] fix typo. --- .../spark/sql/catalyst/expressions/collationExpressions.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collationExpressions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collationExpressions.scala index 24d6e74ad2972..effcdc4b038e5 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collationExpressions.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collationExpressions.scala @@ -117,5 +117,5 @@ case class Collation(child: Expression) Literal.create(collationName, SQLConf.get.defaultStringType) } override def inputTypes: Seq[AbstractDataType] = - Seq(StringTypeWithCaseAccentSensitivity(/* supportsBinaryEquality = */ true)) + Seq(StringTypeWithCaseAccentSensitivity(/* supportsTrimCollation = */ true)) } From a57e9e8328fbbd73237bdead4160e1e4919b22d5 Mon Sep 17 00:00:00 2001 From: Jovan Pavlovic Date: Fri, 4 Oct 2024 17:55:18 +0200 Subject: [PATCH 9/9] add negative test. --- .../sql/CollationSQLExpressionsSuite.scala | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/sql/core/src/test/scala/org/apache/spark/sql/CollationSQLExpressionsSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/CollationSQLExpressionsSuite.scala index 851160d2fbb94..4c3cd93873bd4 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/CollationSQLExpressionsSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/CollationSQLExpressionsSuite.scala @@ -982,7 +982,11 @@ class CollationSQLExpressionsSuite StringToMapTestCase("1/AX2/BX3/C", "x", "/", "UNICODE_CI", Map("1" -> "A", "2" -> "B", "3" -> "C")) ) - val unsupportedTestCase = StringToMapTestCase("a:1,b:2,c:3", "?", "?", "UNICODE_AI", null) + val unsupportedTestCases = Seq( + StringToMapTestCase("a:1,b:2,c:3", "?", "?", "UNICODE_AI", null), + StringToMapTestCase("a:1,b:2,c:3", "?", "?", "UNICODE_RTRIM", null), + StringToMapTestCase("a:1,b:2,c:3", "?", "?", "UTF8_BINARY_RTRIM", null), + StringToMapTestCase("a:1,b:2,c:3", "?", "?", "UTF8_LCASE_RTRIM", null)) testCases.foreach(t => { // Unit test. val text = Literal.create(t.text, StringType(t.collation)) @@ -998,28 +1002,30 @@ class CollationSQLExpressionsSuite } }) // Test unsupported collation. - withSQLConf(SQLConf.DEFAULT_COLLATION.key -> unsupportedTestCase.collation) { - val query = - s"select str_to_map('${unsupportedTestCase.text}', '${unsupportedTestCase.pairDelim}', " + - s"'${unsupportedTestCase.keyValueDelim}')" - checkError( - exception = intercept[AnalysisException] { - sql(query).collect() - }, - condition = "DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE", - sqlState = Some("42K09"), - parameters = Map( - "sqlExpr" -> ("\"str_to_map('a:1,b:2,c:3' collate UNICODE_AI, " + - "'?' collate UNICODE_AI, '?' collate UNICODE_AI)\""), - "paramIndex" -> "first", - "inputSql" -> "\"'a:1,b:2,c:3' collate UNICODE_AI\"", - "inputType" -> "\"STRING COLLATE UNICODE_AI\"", - "requiredType" -> "\"STRING\""), - context = ExpectedContext( - fragment = "str_to_map('a:1,b:2,c:3', '?', '?')", - start = 7, - stop = 41)) - } + unsupportedTestCases.foreach(t => { + withSQLConf(SQLConf.DEFAULT_COLLATION.key -> t.collation) { + val query = + s"select str_to_map('${t.text}', '${t.pairDelim}', " + + s"'${t.keyValueDelim}')" + checkError( + exception = intercept[AnalysisException] { + sql(query).collect() + }, + condition = "DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE", + sqlState = Some("42K09"), + parameters = Map( + "sqlExpr" -> ("\"str_to_map('a:1,b:2,c:3' collate " + s"${t.collation}, " + + "'?' collate " + s"${t.collation}, '?' collate ${t.collation})" + "\""), + "paramIndex" -> "first", + "inputSql" -> ("\"'a:1,b:2,c:3' collate " + s"${t.collation}" + "\""), + "inputType" -> ("\"STRING COLLATE " + s"${t.collation}" + "\""), + "requiredType" -> "\"STRING\""), + context = ExpectedContext( + fragment = "str_to_map('a:1,b:2,c:3', '?', '?')", + start = 7, + stop = 41)) + } + }) } test("Support RaiseError misc expression with collation") {