diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java index 650403098b07..d966cc0f0dc4 100644 --- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java @@ -879,6 +879,22 @@ public static String translateWithCharset(String s, String transcodingName) { } /** SQL {@code PARSE_URL(urlStr, partToExtract [, keyToExtract] )} function. */ + public static @Nullable String parseUrl(@Nullable String urlStr, + @Nullable String partToExtract, @Nullable String keyToExtract) { + if (partToExtract == null || !partToExtract.equals("QUERY")) { + return null; + } + + String query = parseUrl(urlStr, partToExtract); + if (query == null) { + return null; + } + + Pattern p = Pattern.compile("(&|^)" + keyToExtract + "=([^&]*)"); + Matcher m = p.matcher(query); + return m.find() ? m.group(2) : null; + } + public static @Nullable String parseUrl(@Nullable String urlStr, @Nullable String partToExtract) { if (urlStr == null || partToExtract == null) { @@ -930,30 +946,12 @@ public static String translateWithCharset(String s, String transcodingName) { extractValue = uri.getRawUserInfo(); break; default: - return null; + extractValue = null; + break; } return extractValue; } - public static @Nullable String parseUrl(@Nullable String urlStr, - @Nullable String partToExtract, @Nullable String keyToExtract) { - if (partToExtract == null || !partToExtract.equals("QUERY")) { - return null; - } - - String query = parseUrl(urlStr, partToExtract); - if (query == null) { - return null; - } - - Pattern p = Pattern.compile("(&|^)" + keyToExtract + "=([^&]*)"); - Matcher m = p.matcher(query); - if (m.find()) { - return m.group(2); - } - return null; - } - /** SQL {@code RTRIM} function applied to string. */ public static String rtrim(String s) { return trim(false, true, " ", s); diff --git a/site/_docs/reference.md b/site/_docs/reference.md index 2d4df4bb7c5e..e1a8d39fc9fd 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -2769,7 +2769,7 @@ BigQuery's type system uses confusingly different names for types and functions: | b | PARSE_DATETIME(format, string) | Uses format specified by *format* to convert *string* representation of datetime to a TIMESTAMP value | b | PARSE_TIME(format, string) | Uses format specified by *format* to convert *string* representation of time to a TIME value | b | PARSE_TIMESTAMP(format, string[, timeZone]) | Uses format specified by *format* to convert *string* representation of timestamp to a TIMESTAMP WITH LOCAL TIME ZONE value in *timeZone* -| h s | PARSE_URL(urlString, partToExtract [, keyToExtract] ) | Returns the specified part from the *urlString*. Valid values for *partToExtract* include HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO +| h s | PARSE_URL(urlString, partToExtract [, keyToExtract] ) | Returns the specified part from the *urlString*. Valid values for *partToExtract* include HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO. *keyToExtract* specifies which query to extract | b | POW(numeric1, numeric2) | Returns *numeric1* raised to the power *numeric2* | m o | REGEXP_REPLACE(string, regexp, rep [, pos [, occurrence [, matchType]]]) | Replaces all substrings of *string* that match *regexp* with *rep* at the starting *pos* in expr (if omitted, the default is 1), *occurrence* means which occurrence of a match to search for (if omitted, the default is 1), *matchType* specifies how to perform matching | b m p | REPEAT(string, integer) | Returns a string consisting of *string* repeated of *integer* times; returns an empty string if *integer* is less than 1 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 d3a9d10afc65..30e094d9cf8c 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -4013,7 +4013,17 @@ static void checkRlikeFails(SqlOperatorFixture f) { // test with invalid partToExtract f.checkNull("parse_url('http://calcite.apache.org/path1/p.php?k1=v1&k2=v2#Ref1'," - + " 'INVALID_PART_TO_EXTRACT')"); + + " 'INVALID_PART_TO_EXTRACT')"); + f.checkNull("parse_url('http://calcite.apache.org/path1/p.php?k1=v1&k2=v2#Ref1'," + + " 'HOST', 'k1')"); + + // test with invalid urlString + f.checkNull("parse_url('http:calcite.apache.org/path1/p.php?k1=v1&k2=v2#Ref1'," + + " 'HOST')"); + f.checkNull("parse_url('calcite.apache.org/path1/p.php?k1=v1&k2=v2#Ref1'," + + " 'HOST')"); + f.checkNull("parse_url('/path1/p.php?k1=v1&k2=v2#Ref1'," + + " 'HOST')"); // test with operands with null values f.checkNull("parse_url('http://calcite.apache.org/path1/p.php?k1=v1&k2=v2#Ref1',"