asfgit closed pull request #6337: [FLINK-9853] [table] Add HEX support URL: https://github.com/apache/flink/pull/6337
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/docs/dev/table/sql.md b/docs/dev/table/sql.md index 148f30727d9..09b9b261b68 100644 --- a/docs/dev/table/sql.md +++ b/docs/dev/table/sql.md @@ -1675,6 +1675,17 @@ BIN(numeric) </td> </tr> + <tr> + <td> +{% highlight text %} +HEX(numeric) +HEX(string) + {% endhighlight %} + </td> + <td> + <p>Returns a string representation of an integer numeric value or a string in hex format. Returns null if numeric is null. E.g. For numeric "20" leads to "14", "100" leads to "64", and for string "hello,world" leads to "68656c6c6f2c776f726c64".</p> + </td> + </tr> </tbody> </table> diff --git a/docs/dev/table/tableApi.md b/docs/dev/table/tableApi.md index b702dddcde5..b5dd4164a7d 100644 --- a/docs/dev/table/tableApi.md +++ b/docs/dev/table/tableApi.md @@ -2333,6 +2333,17 @@ NUMERIC.bin() </td> </tr> + <tr> + <td> + {% highlight java %} +NUMERIC.hex() +STRING.hex() +{% endhighlight %} + </td> + <td> + <p>Returns a string representation of an integer numeric value or a string in hex format. Returns null if numeric is null. E.g. For numeric "20" leads to "14", "100" leads to "64", and for string "hello,world" leads to "68656c6c6f2c776f726c64".</p> + </td> + </tr> </tbody> </table> @@ -3921,6 +3932,17 @@ NUMERIC.bin() </td> </tr> + <tr> + <td> + {% highlight scala %} +NUMERIC.hex() +STRING.hex() +{% endhighlight %} + </td> + <td> + <p>Returns a string representation of an integer numeric value or a string in hex format. Returns null if numeric is null. E.g. For numeric "20" leads to "14", "100" leads to "64", and for string "hello,world" leads to "68656c6c6f2c776f726c64".</p> + </td> + </tr> </tbody> </table> diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/api/scala/expressionDsl.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/api/scala/expressionDsl.scala index c7c805f6743..1df30d98d11 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/api/scala/expressionDsl.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/api/scala/expressionDsl.scala @@ -406,6 +406,13 @@ trait ImplicitExpressionOperations { */ def bin() = Bin(expr) + /** + * Returns a string representation of an integer numeric value or a string in hex format. + * Returns null if numeric or string is null. E.g. For numeric "20" leads to "14", + * "100" leads to "64", and for string "hello,world" leads to "68656c6c6f2c776f726c64". + */ + def hex() = Hex(expr) + // String operations /** diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/BuiltInMethods.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/BuiltInMethods.scala index f5ed9b387de..1e21bfe7830 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/BuiltInMethods.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/BuiltInMethods.scala @@ -132,6 +132,11 @@ object BuiltInMethods { val BIN = Types.lookupMethod(classOf[JLong], "toBinaryString", classOf[Long]) + val HEX = Types.lookupMethod(classOf[ScalarFunctions], "hex", classOf[Long]) + + val HEX_STRING = + Types.lookupMethod(classOf[ScalarFunctions], "hexString", classOf[String]) + val FROMBASE64 = Types.lookupMethod(classOf[ScalarFunctions], "fromBase64", classOf[String]) val TOBASE64 = Types.lookupMethod(classOf[ScalarFunctions], "toBase64", classOf[String]) diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/FunctionGenerator.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/FunctionGenerator.scala index 74b69d6afcc..47f54fb229c 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/FunctionGenerator.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/FunctionGenerator.scala @@ -455,6 +455,18 @@ object FunctionGenerator { STRING_TYPE_INFO, BuiltInMethods.BIN) + addSqlFunctionMethod( + ScalarSqlFunctions.HEX, + Seq(LONG_TYPE_INFO), + STRING_TYPE_INFO, + BuiltInMethods.HEX) + + addSqlFunctionMethod( + ScalarSqlFunctions.HEX, + Seq(STRING_TYPE_INFO), + STRING_TYPE_INFO, + BuiltInMethods.HEX_STRING) + // ---------------------------------------------------------------------------------------------- // Temporal functions // ---------------------------------------------------------------------------------------------- diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/expressions/mathExpressions.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/expressions/mathExpressions.scala index cf3efa938a6..728eac62e71 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/expressions/mathExpressions.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/expressions/mathExpressions.scala @@ -422,3 +422,21 @@ case class Bin(child: Expression) extends UnaryExpression { relBuilder.call(ScalarSqlFunctions.BIN, child.toRexNode) } } + +case class Hex(child: Expression) extends UnaryExpression { + override private[flink] def resultType: TypeInformation[_] = BasicTypeInfo.STRING_TYPE_INFO + + override private[flink] def validateInput(): ValidationResult = { + if (TypeCheckUtils.isIntegerFamily(child.resultType) || + TypeCheckUtils.isString(child.resultType)) { + ValidationSuccess + } else { + ValidationFailure(s"hex requires integer or string types but was '${child.resultType}'.") + } + } + override def toString: String = s"hex($child)" + + override private[flink] def toRexNode(implicit relBuilder: RelBuilder): RexNode = { + relBuilder.call(ScalarSqlFunctions.HEX, child.toRexNode) + } +} diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/functions/sql/ScalarSqlFunctions.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/functions/sql/ScalarSqlFunctions.scala index 21793e3351c..a0b6c9c67cf 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/functions/sql/ScalarSqlFunctions.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/functions/sql/ScalarSqlFunctions.scala @@ -42,6 +42,15 @@ object ScalarSqlFunctions { OperandTypes.family(SqlTypeFamily.INTEGER), SqlFunctionCategory.NUMERIC) + val HEX = new SqlFunction( + "HEX", + SqlKind.OTHER_FUNCTION, + ReturnTypes.cascade(ReturnTypes.explicit(SqlTypeName.VARCHAR), SqlTypeTransforms.TO_NULLABLE), + InferTypes.RETURN_TYPE, + OperandTypes.or(OperandTypes.family(SqlTypeFamily.INTEGER), + OperandTypes.family(SqlTypeFamily.STRING)), + SqlFunctionCategory.NUMERIC) + val CONCAT = new SqlFunction( "CONCAT", SqlKind.OTHER_FUNCTION, diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/runtime/functions/ScalarFunctions.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/runtime/functions/ScalarFunctions.scala index 03ee62ce224..491fdd7b405 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/runtime/functions/ScalarFunctions.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/runtime/functions/ScalarFunctions.scala @@ -19,8 +19,9 @@ package org.apache.flink.table.runtime.functions import scala.annotation.varargs import java.math.{BigDecimal => JBigDecimal} -import java.lang.StringBuilder +import java.lang.{Long => JLong, StringBuilder} +import org.apache.commons.codec.binary.Hex import org.apache.commons.codec.binary.Base64 /** @@ -202,6 +203,13 @@ object ScalarFunctions { new String(data) } + /** + * Returns the string str that is encoded as hex string of x. + */ + def hex(x: Long): String = JLong.toHexString(x).toUpperCase() + + def hexString(x: String): String = Hex.encodeHexString(x.getBytes).toUpperCase() + /** * Returns the base string decoded with base64. */ diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/validate/FunctionCatalog.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/validate/FunctionCatalog.scala index bca156c261a..a446401f31c 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/validate/FunctionCatalog.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/validate/FunctionCatalog.scala @@ -239,6 +239,7 @@ object FunctionCatalog { "rand" -> classOf[Rand], "randInteger" -> classOf[RandInteger], "bin" -> classOf[Bin], + "hex" -> classOf[Hex], // temporal functions "extract" -> classOf[Extract], @@ -438,6 +439,7 @@ class BasicOperatorTable extends ReflectiveSqlOperatorTable { ScalarSqlFunctions.CONCAT, ScalarSqlFunctions.CONCAT_WS, ScalarSqlFunctions.BIN, + ScalarSqlFunctions.HEX, SqlStdOperatorTable.TIMESTAMP_ADD, ScalarSqlFunctions.LOG, ScalarSqlFunctions.LPAD, diff --git a/flink-libraries/flink-table/src/test/scala/org/apache/flink/table/expressions/ScalarFunctionsTest.scala b/flink-libraries/flink-table/src/test/scala/org/apache/flink/table/expressions/ScalarFunctionsTest.scala index 6f9a9ae81b9..7f5b156202a 100644 --- a/flink-libraries/flink-table/src/test/scala/org/apache/flink/table/expressions/ScalarFunctionsTest.scala +++ b/flink-libraries/flink-table/src/test/scala/org/apache/flink/table/expressions/ScalarFunctionsTest.scala @@ -392,6 +392,93 @@ class ScalarFunctionsTest extends ScalarTypesTestBase { "รครครค1234512345") } + @Test + def testHex(): Unit = { + testAllApis( + 100.hex(), + "100.hex()", + "HEX(100)", + "64") + + testAllApis( + 'f2.hex(), + "f2.hex()", + "HEX(f2)", + "2A") + + testAllApis( + Null(Types.BYTE).hex(), + "hex(Null(BYTE))", + "HEX(CAST(NULL AS TINYINT))", + "null") + + testAllApis( + 'f3.hex(), + "f3.hex()", + "HEX(f3)", + "2B") + + testAllApis( + 'f4.hex(), + "f4.hex()", + "HEX(f4)", + "2C") + + testAllApis( + 'f7.hex(), + "f7.hex()", + "HEX(f7)", + "3") + + testAllApis( + 12.hex(), + "12.hex()", + "HEX(12)", + "C") + + testAllApis( + 10.hex(), + "10.hex()", + "HEX(10)", + "A") + + testAllApis( + 0.hex(), + "0.hex()", + "HEX(0)", + "0") + + testAllApis( + 'f32.hex(), + "f32.hex()", + "HEX(f32)", + "FFFFFFFFFFFFFFFF") + + testAllApis( + 'f0.hex(), + "f0.hex()", + "HEX(f0)", + "546869732069732061207465737420537472696E672E") + + testAllApis( + 'f8.hex(), + "f8.hex()", + "HEX(f8)", + "20546869732069732061207465737420537472696E672E20") + + testAllApis( + 'f23.hex(), + "f23.hex()", + "HEX(f23)", + "25546869732069732061207465737420537472696E672E") + + testAllApis( + 'f24.hex(), + "f24.hex()", + "HEX(f24)", + "2A5F546869732069732061207465737420537472696E672E") + } + @Test def testBin(): Unit = { ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services