diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/HiveSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/HiveSqlDialect.java index db57e5affed..689ecc1ecf6 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/HiveSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/HiveSqlDialect.java @@ -129,6 +129,9 @@ public HiveSqlDialect(Context context) { case TRIM: RelToSqlConverterUtil.unparseHiveTrim(writer, call, leftPrec, rightPrec); break; + case RLIKE: + RelToSqlConverterUtil.unparseRegexp(writer, call, leftPrec, rightPrec); + break; default: super.unparseCall(writer, call, leftPrec, rightPrec); } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java index 947223b682a..2479a92ba24 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java @@ -705,11 +705,10 @@ static RelDataType deriveTypeSplit(SqlOperatorBinding operatorBinding, public static final SqlFunction REGEXP_SUBSTR = REGEXP_EXTRACT.withName("REGEXP_SUBSTR"); /** The "REGEXP(value, regexp)" function, equivalent to {@link #RLIKE}. */ - @LibraryOperator(libraries = {SPARK}) + @LibraryOperator(libraries = {SPARK, HIVE}) public static final SqlFunction REGEXP = - SqlBasicFunction.create("REGEXP", ReturnTypes.BOOLEAN_NULLABLE, - OperandTypes.STRING_STRING, - SqlFunctionCategory.STRING); + SqlBasicFunction.create("REGEXP", SqlKind.RLIKE, ReturnTypes.BOOLEAN_NULLABLE, + OperandTypes.STRING_STRING); /** The "REGEXP_LIKE(value, regexp)" function, equivalent to {@link #RLIKE}. */ @LibraryOperator(libraries = {SPARK, MYSQL, POSTGRESQL, ORACLE}) diff --git a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java index ddb37e8dac3..975bfc8505b 100644 --- a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java +++ b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java @@ -445,4 +445,19 @@ public ClickHouseSqlArrayTypeNameSpec(SqlTypeNameSpec elementTypeName, writer.endList(frame); } } + + /** + * Unparses REGEXP function calls by converting from function call format + * (e.g., REGEXP(column, pattern)) to infix operator format (e.g., column REGEXP pattern). + */ + public static void unparseRegexp(SqlWriter writer, SqlCall call, int leftPrec, int rightPrec) { + if ("REGEXP".equals(call.getOperator().getName())) { + final SqlWriter.Frame frame = writer.startList(SqlWriter.FrameTypeEnum.SIMPLE, "(", ")"); + call.operand(0).unparse(writer, leftPrec, rightPrec); + writer.sep("REGEXP", true); + call.operand(1).unparse(writer, leftPrec, rightPrec); + writer.endList(frame); + } + } + } diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java index a98f7fd1f8f..7f9f10e5578 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java @@ -11761,4 +11761,36 @@ public Sql schema(CalciteAssert.SchemaSpec schemaSpec) { .ok(expected); } + /** Test case for + * [CALCITE-7428] + * Support regexp function change regexp operator for Hive library. */ + @Test void testRegexpWithHive() { + final String query = "select \"brand_name\"\n" + + "from \"product\" where REGEXP(\"brand_name\",'[a-zA-Z]') "; + final String expectedHive = "SELECT `brand_name`\nFROM " + + "`foodmart`.`product`\nWHERE (`brand_name` REGEXP '[a-zA-Z]')"; + sql(query).withLibrary(SqlLibrary.HIVE).withHive().ok(expectedHive); + } + + /** Test case for + * [CALCITE-7428] + * Support regexp function change regexp operator for Hive library. */ + @Test void testRegexpWithHiveIsNotNull() { + final String query = "select \"brand_name\"\n" + + "from \"product\" where REGEXP(\"brand_name\",'[a-zA-Z]') is not null "; + final String expectedHive = "SELECT `brand_name`\nFROM " + + "`foodmart`.`product`\nWHERE (`brand_name` REGEXP '[a-zA-Z]') IS NOT NULL"; + sql(query).withLibrary(SqlLibrary.HIVE).withHive().ok(expectedHive); + } + + /** Test case for + * [CALCITE-7428] + * Support regexp function change regexp operator for Hive library. */ + @Test void testSelectRegexpWithHiveIsNotNull() { + final String query = "select REGEXP(\"brand_name\",'[a-zA-Z]') is not null \n" + + "from \"product\""; + final String expectedHive = "SELECT (`brand_name` REGEXP '[a-zA-Z]') IS NOT NULL\n" + + "FROM `foodmart`.`product`"; + sql(query).withLibrary(SqlLibrary.HIVE).withHive().ok(expectedHive); + } } diff --git a/site/_docs/reference.md b/site/_docs/reference.md index e1ea8e72069..ee3d2d739f8 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -3004,7 +3004,7 @@ In the following: | b s | POW(numeric1, numeric2) | Returns *numeric1* raised to the power *numeric2* | b c h q m o f s p r | POWER(numeric1, numeric2) | Returns *numeric1* raised to the power of *numeric2* | p r | RANDOM() | Generates a random double between 0 and 1 inclusive -| s | REGEXP(string, regexp) | Equivalent to `string1 RLIKE string2` +| s h | REGEXP(string, regexp) | Equivalent to `string1 RLIKE string2` | b | REGEXP_CONTAINS(string, regexp) | Returns whether *string* is a partial match for the *regexp* | b | REGEXP_EXTRACT(string, regexp [, position [, occurrence]]) | Returns the substring in *string* that matches the *regexp*, starting search at *position* (default 1), and until locating the nth *occurrence* (default 1). Returns NULL if there is no match | b | REGEXP_EXTRACT_ALL(string, regexp) | Returns an array of all substrings in *string* that matches the *regexp*. Returns an empty array if there is no match diff --git a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java index 41b45d3c761..b6731f9e63f 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -4232,6 +4232,7 @@ void checkIsNull(SqlOperatorFixture f, SqlOperator operator) { checkRlikeFunc(f, SqlLibrary.HIVE, SqlLibraryOperators.RLIKE); checkRlikeFunc(f, SqlLibrary.SPARK, SqlLibraryOperators.RLIKE); checkRlikeFunc(f, SqlLibrary.SPARK, SqlLibraryOperators.REGEXP); + checkRlikeFunc(f, SqlLibrary.HIVE, SqlLibraryOperators.REGEXP); checkRlikeFunc(f, SqlLibrary.MYSQL, SqlLibraryOperators.RLIKE); checkNotRlikeFunc(f.withLibrary(SqlLibrary.HIVE)); checkNotRlikeFunc(f.withLibrary(SqlLibrary.SPARK));