diff --git a/core/trino-main/src/main/java/io/trino/operator/scalar/UrlFunctions.java b/core/trino-main/src/main/java/io/trino/operator/scalar/UrlFunctions.java index 823916b4a516..6c84b6c42425 100644 --- a/core/trino-main/src/main/java/io/trino/operator/scalar/UrlFunctions.java +++ b/core/trino-main/src/main/java/io/trino/operator/scalar/UrlFunctions.java @@ -34,7 +34,6 @@ import java.net.URLDecoder; import java.util.Iterator; -import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Strings.nullToEmpty; import static io.airlift.slice.Slices.utf8Slice; import static io.trino.spi.StandardErrorCode.INVALID_FUNCTION_ARGUMENT; @@ -54,8 +53,8 @@ private UrlFunctions() {} @SqlType("varchar(x)") public static Slice urlExtractProtocol(@SqlType("varchar(x)") Slice url) { - URI uri = parseUriArgument(url); - return slice(uri.getScheme()); + URI uri = parseUrl(url); + return (uri == null) ? null : slice(uri.getScheme()); } @SqlNullable @@ -65,8 +64,8 @@ public static Slice urlExtractProtocol(@SqlType("varchar(x)") Slice url) @SqlType("varchar(x)") public static Slice urlExtractHost(@SqlType("varchar(x)") Slice url) { - URI uri = parseUriArgument(url); - return slice(uri.getHost()); + URI uri = parseUrl(url); + return (uri == null) ? null : slice(uri.getHost()); } @SqlNullable @@ -76,8 +75,8 @@ public static Slice urlExtractHost(@SqlType("varchar(x)") Slice url) @SqlType(StandardTypes.BIGINT) public static Long urlExtractPort(@SqlType("varchar(x)") Slice url) { - URI uri = parseUriArgument(url); - if (uri.getPort() < 0) { + URI uri = parseUrl(url); + if ((uri == null) || (uri.getPort() < 0)) { return null; } return (long) uri.getPort(); @@ -90,8 +89,8 @@ public static Long urlExtractPort(@SqlType("varchar(x)") Slice url) @SqlType("varchar(x)") public static Slice urlExtractPath(@SqlType("varchar(x)") Slice url) { - URI uri = parseUriArgument(url); - return slice(uri.getPath()); + URI uri = parseUrl(url); + return (uri == null) ? null : slice(uri.getPath()); } @SqlNullable @@ -101,8 +100,8 @@ public static Slice urlExtractPath(@SqlType("varchar(x)") Slice url) @SqlType("varchar(x)") public static Slice urlExtractQuery(@SqlType("varchar(x)") Slice url) { - URI uri = parseUriArgument(url); - return slice(uri.getQuery()); + URI uri = parseUrl(url); + return (uri == null) ? null : slice(uri.getQuery()); } @SqlNullable @@ -112,8 +111,8 @@ public static Slice urlExtractQuery(@SqlType("varchar(x)") Slice url) @SqlType("varchar(x)") public static Slice urlExtractFragment(@SqlType("varchar(x)") Slice url) { - URI uri = parseUriArgument(url); - return slice(uri.getFragment()); + URI uri = parseUrl(url); + return (uri == null) ? null : slice(uri.getFragment()); } @SqlNullable @@ -123,8 +122,8 @@ public static Slice urlExtractFragment(@SqlType("varchar(x)") Slice url) @SqlType("varchar(x)") public static Slice urlExtractParameter(@SqlType("varchar(x)") Slice url, @SqlType("varchar(y)") Slice parameterName) { - URI uri = parseUriArgument(url); - if (uri.getRawQuery() == null) { + URI uri = parseUrl(url); + if ((uri == null) || (uri.getRawQuery() == null)) { return null; } @@ -185,13 +184,13 @@ private static Slice slice(@Nullable String s) } @Nullable - private static URI parseUriArgument(Slice url) + private static URI parseUrl(Slice url) { try { return new URI(url.toStringUtf8()); } catch (URISyntaxException e) { - throw new TrinoException(INVALID_FUNCTION_ARGUMENT, "Cannot parse as URI value '%s': %s".formatted(url.toStringUtf8(), firstNonNull(e.getMessage(), e)), e); + return null; } } } diff --git a/core/trino-main/src/test/java/io/trino/operator/scalar/TestUrlFunctions.java b/core/trino-main/src/test/java/io/trino/operator/scalar/TestUrlFunctions.java index 88efd14a7b85..f5aaa6af182a 100644 --- a/core/trino-main/src/test/java/io/trino/operator/scalar/TestUrlFunctions.java +++ b/core/trino-main/src/test/java/io/trino/operator/scalar/TestUrlFunctions.java @@ -19,11 +19,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; -import static com.google.common.base.Preconditions.checkArgument; -import static io.trino.spi.StandardErrorCode.INVALID_FUNCTION_ARGUMENT; import static io.trino.spi.type.BigintType.BIGINT; import static io.trino.spi.type.VarcharType.createVarcharType; -import static io.trino.testing.assertions.TrinoExceptionAssert.assertTrinoExceptionThrownBy; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; @@ -56,9 +53,7 @@ public void testUrlExtract() validateUrlExtract("https://username:password@example.com", "https", "example.com", null, "", "", ""); validateUrlExtract("mailto:test@example.com", "mailto", "", null, "", "", ""); validateUrlExtract("foo", "", "", null, "foo", "", ""); - - invalidUrlExtract("http://example.com/^"); - invalidUrlExtract("http://not uri/cannot contain whitespace"); + validateUrlExtract("http://example.com/^", null, null, null, null, null, null); } @Test @@ -101,10 +96,6 @@ public void testUrlExtractParameter() assertThat(assertions.expression("url_extract_parameter('foo', 'k1')")) .isNull(createVarcharType(3)); - - assertTrinoExceptionThrownBy(() -> assertions.expression("url_extract_parameter('http://not uri/cannot contain whitespace?foo=bar', 'foo')").evaluate()) - .hasErrorCode(INVALID_FUNCTION_ARGUMENT) - .hasMessage("Cannot parse as URI value 'http://not uri/cannot contain whitespace?foo=bar': Illegal character in authority at index 7: http://not uri/cannot contain whitespace?foo=bar"); } @Test @@ -153,8 +144,6 @@ public void testUrlDecode() private void validateUrlExtract(String url, String protocol, String host, Long port, String path, String query, String fragment) { - checkArgument(!url.contains("'")); // Would require escaping in literals - assertThat(assertions.function("url_extract_protocol", "'" + url + "'")) .hasType(createVarcharType(url.length())) .isEqualTo(protocol); @@ -179,33 +168,4 @@ private void validateUrlExtract(String url, String protocol, String host, Long p .hasType(createVarcharType(url.length())) .isEqualTo(fragment); } - - private void invalidUrlExtract(String url) - { - checkArgument(!url.contains("'")); // Would require escaping in literals - - assertTrinoExceptionThrownBy(() -> assertions.function("url_extract_protocol", "'" + url + "'").evaluate()) - .hasErrorCode(INVALID_FUNCTION_ARGUMENT) - .hasMessageStartingWith("Cannot parse as URI value '%s': ".formatted(url)); - - assertTrinoExceptionThrownBy(() -> assertions.function("url_extract_host", "'" + url + "'").evaluate()) - .hasErrorCode(INVALID_FUNCTION_ARGUMENT) - .hasMessageStartingWith("Cannot parse as URI value '%s': ".formatted(url)); - - assertTrinoExceptionThrownBy(() -> assertions.function("url_extract_port", "'" + url + "'").evaluate()) - .hasErrorCode(INVALID_FUNCTION_ARGUMENT) - .hasMessageStartingWith("Cannot parse as URI value '%s': ".formatted(url)); - - assertTrinoExceptionThrownBy(() -> assertions.function("url_extract_path", "'" + url + "'").evaluate()) - .hasErrorCode(INVALID_FUNCTION_ARGUMENT) - .hasMessageStartingWith("Cannot parse as URI value '%s': ".formatted(url)); - - assertTrinoExceptionThrownBy(() -> assertions.function("url_extract_query", "'" + url + "'").evaluate()) - .hasErrorCode(INVALID_FUNCTION_ARGUMENT) - .hasMessageStartingWith("Cannot parse as URI value '%s': ".formatted(url)); - - assertTrinoExceptionThrownBy(() -> assertions.function("url_extract_fragment", "'" + url + "'").evaluate()) - .hasErrorCode(INVALID_FUNCTION_ARGUMENT) - .hasMessageStartingWith("Cannot parse as URI value '%s': ".formatted(url)); - } }