This is an automated email from the ASF dual-hosted git repository.
snuyanzin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git
The following commit(s) were added to refs/heads/master by this push:
new f03c9044268 [FLINK-39868][table-runtime] Remove per-row logging from
`parseUrl` and `subString`
f03c9044268 is described below
commit f03c904426853ad3a62883d196b4f6b07c7ef365
Author: Ramin Gharib <[email protected]>
AuthorDate: Wed Jun 10 09:40:03 2026 +0200
[FLINK-39868][table-runtime] Remove per-row logging from `parseUrl` and
`subString`
---
.../planner/functions/StringFunctionsITCase.java | 237 ++++++++++++++++++++-
.../planner/expressions/ScalarFunctionsTest.scala | 162 --------------
.../table/runtime/functions/SqlFunctionUtils.java | 8 -
3 files changed, 235 insertions(+), 172 deletions(-)
diff --git
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/StringFunctionsITCase.java
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/StringFunctionsITCase.java
index e3b7e077aff..0fd1c53dac9 100644
---
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/StringFunctionsITCase.java
+++
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/StringFunctionsITCase.java
@@ -41,12 +41,15 @@ class StringFunctionsITCase extends BuiltInFunctionTestBase
{
Stream<TestSetSpec> getTestSetSpecs() {
return Stream.of(
bTrimTestCases(),
+ concatenateTestCases(),
eltTestCases(),
endsWithTestCases(),
+ parseUrlTestCases(),
printfTestCases(),
startsWithTestCases(),
- translateTestCases(),
- concatenateTestCases())
+ substrTestCases(),
+ substringTestCases(),
+ translateTestCases())
.flatMap(s -> s);
}
@@ -752,4 +755,234 @@ class StringFunctionsITCase extends
BuiltInFunctionTestBase {
"Invalid input arguments. Expected signatures
are:\n"
+ "TRANSLATE3(expr <CHARACTER_STRING>,
fromStr <CHARACTER_STRING>, toStr <CHARACTER_STRING>)"));
}
+
+ private Stream<TestSetSpec> parseUrlTestCases() {
+ return Stream.of(
+ parseUrl("http://[email protected]/path?query=1#Ref")
+ .part("HOST", "flink.apache.org")
+ .part("PATH", "/path")
+ .part("QUERY", "query=1")
+ .part("REF", "Ref")
+ .part("PROTOCOL", "http")
+ .part("FILE", "/path?query=1")
+ .part("AUTHORITY", "[email protected]")
+ .part("USERINFO", "userinfo")
+ .queryParam("query", "1")
+ .toSpec(),
+ parseUrl(
+
"https://use%20r:pas%[email protected]/dir%20/pa%20th.HTML?query=x%20y&q2=2#Ref%20two")
+ .part("HOST", "example.com")
+ .part("PATH", "/dir%20/pa%20th.HTML")
+ .part("QUERY", "query=x%20y&q2=2")
+ .part("REF", "Ref%20two")
+ .part("PROTOCOL", "https")
+ .part("FILE", "/dir%20/pa%20th.HTML?query=x%20y&q2=2")
+ .part("AUTHORITY", "use%20r:pas%[email protected]")
+ .part("USERINFO", "use%20r:pas%20s")
+ .queryParam("query", "x%20y")
+ .queryParam("q2", "2")
+ .toSpec(),
+ parseUrl("http://user:pass@host")
+ .part("HOST", "host")
+ .part("PATH", "")
+ .part("QUERY", null)
+ .part("REF", null)
+ .part("PROTOCOL", "http")
+ .part("FILE", "")
+ .part("AUTHORITY", "user:pass@host")
+ .part("USERINFO", "user:pass")
+ .queryParam("query", null)
+ .toSpec(),
+ parseUrl("http://user:pass@host/")
+ .part("HOST", "host")
+ .part("PATH", "/")
+ .part("QUERY", null)
+ .part("REF", null)
+ .part("PROTOCOL", "http")
+ .part("FILE", "/")
+ .part("AUTHORITY", "user:pass@host")
+ .part("USERINFO", "user:pass")
+ .queryParam("query", null)
+ .toSpec(),
+ parseUrl("http://user:pass@host/?#")
+ .part("HOST", "host")
+ .part("PATH", "/")
+ .part("QUERY", "")
+ .part("REF", "")
+ .part("PROTOCOL", "http")
+ .part("FILE", "/?")
+ .part("AUTHORITY", "user:pass@host")
+ .part("USERINFO", "user:pass")
+ .queryParam("query", null)
+ .toSpec(),
+ parseUrl("http://user:pass@host/file;param?query;p2")
+ .part("HOST", "host")
+ .part("PATH", "/file;param")
+ .part("QUERY", "query;p2")
+ .part("REF", null)
+ .part("PROTOCOL", "http")
+ .part("FILE", "/file;param?query;p2")
+ .part("AUTHORITY", "user:pass@host")
+ .part("USERINFO", "user:pass")
+ .queryParam("query", null)
+ .toSpec(),
+ parseUrl("invalid://user:pass@host/file;param?query;p2")
+ .part("HOST", null)
+ .part("PATH", null)
+ .part("QUERY", null)
+ .part("REF", null)
+ .part("PROTOCOL", null)
+ .part("FILE", null)
+ .part("AUTHORITY", null)
+ .part("USERINFO", null)
+ .queryParam("query", null)
+ .toSpec());
+ }
+
+ private ParseUrlCases parseUrl(String url) {
+ return new ParseUrlCases(url);
+ }
+
+ /** Fluent builder for PARSE_URL specs: one self-describing line per
extracted URL part. */
+ private static final class ParseUrlCases {
+ private TestSetSpec spec;
+
+ ParseUrlCases(String url) {
+ spec =
+
TestSetSpec.forFunction(BuiltInFunctionDefinitions.PARSE_URL, url)
+ .onFieldsWithData(url)
+ .andDataTypes(DataTypes.STRING());
+ }
+
+ ParseUrlCases part(String part, String expected) {
+ spec =
+ spec.testResult(
+ $("f0").parseUrl(part),
+ "PARSE_URL(f0, '" + part + "')",
+ expected,
+ DataTypes.STRING());
+ return this;
+ }
+
+ ParseUrlCases queryParam(String key, String expected) {
+ spec =
+ spec.testResult(
+ $("f0").parseUrl("QUERY", key),
+ "PARSE_URL(f0, 'QUERY', '" + key + "')",
+ expected,
+ DataTypes.STRING());
+ return this;
+ }
+
+ TestSetSpec toSpec() {
+ return spec;
+ }
+ }
+
+ private Stream<TestSetSpec> substringTestCases() {
+ return Stream.of(
+ TestSetSpec.forFunction(BuiltInFunctionDefinitions.SUBSTRING)
+ .onFieldsWithData("This is a test String.", 3, -3, 1,
"1世3", null)
+ .andDataTypes(
+ DataTypes.STRING(),
+ DataTypes.INT(),
+ DataTypes.INT(),
+ DataTypes.INT(),
+ DataTypes.STRING(),
+ DataTypes.STRING())
+ // two-arg form
+ .testResult(
+ $("f0").substring(2),
+ "SUBSTRING(f0, 2)",
+ "his is a test String.",
+ DataTypes.STRING())
+ // three-arg form
+ .testResult(
+ $("f0").substring(2, 5),
+ "SUBSTRING(f0, 2, 5)",
+ "his i",
+ DataTypes.STRING())
+ .testResult(
+ $("f0").substring(2, 3),
+ "SUBSTRING(f0, 2, 3)",
+ "his",
+ DataTypes.STRING())
+ // start/length from fields
+ .testResult(
+ $("f0").substring(1, $("f1")),
+ "SUBSTRING(f0, 1, f1)",
+ "Thi",
+ DataTypes.STRING())
+ .testResult(
+ $("f0").substring($("f3"), $("f1")),
+ "SUBSTRING(f0, f3, f1)",
+ "Thi",
+ DataTypes.STRING())
+ // start with implicit cast from TINYINT
+ .testResult(
+
$("f0").substring(lit(1).cast(DataTypes.TINYINT()), $("f1")),
+ "SUBSTRING(f0, CAST(1 AS TINYINT), f1)",
+ "Thi",
+ DataTypes.STRING())
+ // multibyte characters counted by code point
+ .testResult(
+ $("f4").substring(1, 2),
+ "SUBSTRING(f4, 1, 2)",
+ "1世",
+ DataTypes.STRING())
+ // length past the end is clamped
+ .testSqlResult(
+ "SUBSTRING(f0, 2, 100)",
+ "his is a test String.",
+ DataTypes.STRING())
+ // start past the end yields empty
+ .testSqlResult("SUBSTRING(f0, 100, 10)", "",
DataTypes.STRING())
+ // negative length yields null
+ .testSqlResult("SUBSTRING(f0, 2, -1)", null,
DataTypes.STRING())
+ .testSqlResult("SUBSTRING(f0, 2, f2)", null,
DataTypes.STRING())
+ // null input yields null
+ .testSqlResult("SUBSTRING(f5, 2, 3)", null,
DataTypes.STRING())
+ .testSqlResult(
+ "SUBSTRING(CAST(NULL AS VARCHAR), 2, 3)",
null, DataTypes.STRING())
+ // SQL FROM/FOR syntax
+ .testSqlResult("SUBSTRING(f0 FROM 2 FOR 1)", "h",
DataTypes.STRING())
+ .testSqlResult(
+ "SUBSTRING(f0 FROM 2)", "his is a test
String.", DataTypes.STRING())
+ .testSqlResult("SUBSTRING(f0 FROM -2)", "g.",
DataTypes.STRING())
+ .testSqlResult("SUBSTRING(f0 FROM -2 FOR 1)", "g",
DataTypes.STRING())
+ .testSqlResult("SUBSTRING(f0 FROM -2 FOR 0)", "",
DataTypes.STRING()));
+ }
+
+ private Stream<TestSetSpec> substrTestCases() {
+ return Stream.of(
+ TestSetSpec.forFunction(BuiltInFunctionDefinitions.SUBSTR)
+ .onFieldsWithData("This is a test String.", 3, -3, 1,
"1世3", null)
+ .andDataTypes(
+ DataTypes.STRING(),
+ DataTypes.INT(),
+ DataTypes.INT(),
+ DataTypes.INT(),
+ DataTypes.STRING(),
+ DataTypes.STRING())
+ .testResult(
+ $("f0").substr(2, 3), "SUBSTR(f0, 2, 3)",
"his", DataTypes.STRING())
+ .testResult(
+ $("f0").substr(2),
+ "SUBSTR(f0, 2)",
+ "his is a test String.",
+ DataTypes.STRING())
+ .testSqlResult(
+ "SUBSTR(f0, 2, 100)", "his is a test String.",
DataTypes.STRING())
+ .testSqlResult("SUBSTR(f0, 100, 10)", "",
DataTypes.STRING())
+ // negative length yields null
+ .testSqlResult("SUBSTR(f0, 2, -1)", null,
DataTypes.STRING())
+ .testSqlResult("SUBSTR(f0, 2, f2)", null,
DataTypes.STRING())
+ // null input yields null
+ .testSqlResult("SUBSTR(f5, 2, 3)", null,
DataTypes.STRING())
+ .testSqlResult(
+ "SUBSTR(CAST(NULL AS VARCHAR), 2, 3)", null,
DataTypes.STRING())
+ .testSqlResult("SUBSTR(f0, f3, f1)", "Thi",
DataTypes.STRING())
+ // multibyte characters counted by code point
+ .testSqlResult("SUBSTR(f4, 1, 2)", "1世",
DataTypes.STRING()));
+ }
}
diff --git
a/flink-table/flink-table-planner/src/test/scala/org/apache/flink/table/planner/expressions/ScalarFunctionsTest.scala
b/flink-table/flink-table-planner/src/test/scala/org/apache/flink/table/planner/expressions/ScalarFunctionsTest.scala
index bede804aa8b..f92847ee3a6 100644
---
a/flink-table/flink-table-planner/src/test/scala/org/apache/flink/table/planner/expressions/ScalarFunctionsTest.scala
+++
b/flink-table/flink-table-planner/src/test/scala/org/apache/flink/table/planner/expressions/ScalarFunctionsTest.scala
@@ -240,30 +240,6 @@ class ScalarFunctionsTest extends ScalarTypesTestBase {
)
}
- @Test
- def testSubstring(): Unit = {
- testAllApis('f0.substring(2), "SUBSTRING(f0, 2)", "his is a test String.")
-
- testAllApis('f0.substring(2, 5), "SUBSTRING(f0, 2, 5)", "his i")
-
- testAllApis('f0.substring(1, 'f7), "SUBSTRING(f0, 1, f7)", "Thi")
-
- testAllApis(
- 'f0.substring(1.cast(DataTypes.TINYINT), 'f7),
- "SUBSTRING(f0, CAST(1 AS TINYINT), f7)",
- "Thi")
-
- testSqlApi("SUBSTRING(f0 FROM 2 FOR 1)", "h")
-
- testSqlApi("SUBSTRING(f0 FROM 2)", "his is a test String.")
-
- testSqlApi("SUBSTRING(f0 FROM -2)", "g.")
-
- testSqlApi("SUBSTRING(f0 FROM -2 FOR 1)", "g")
-
- testSqlApi("SUBSTRING(f0 FROM -2 FOR 0)", "")
- }
-
@Test
def testReplace(): Unit = {
testAllApis('f0.replace(" ", "_"), "REPLACE(f0, ' ', '_')",
"This_is_a_test_String.")
@@ -822,23 +798,6 @@ class ScalarFunctionsTest extends ScalarTypesTestBase {
testSqlApi("to_base64(from_base64(f38))", "AQIDBA==")
}
- @Test
- def testSubString(): Unit = {
- Array("substring", "substr").foreach {
- substr =>
- testAllApis('f0.substr(2, 3), s"$substr(f0, 2, 3)", "his")
- testAllApis('f0.substr(2), s"$substr(f0, 2)", "his is a test String.")
- testSqlApi(s"$substr(f0, 2, 100)", "his is a test String.")
- testSqlApi(s"$substr(f0, 100, 10)", "")
- testSqlApi(s"$substr(f0, 2, -1)", "NULL")
- testSqlApi(s"$substr(f40, 2, 3)", "NULL")
- testSqlApi(s"$substr(CAST(null AS VARCHAR), 2, 3)", "NULL")
- testSqlApi(s"$substr(f0, 2, f14)", "NULL")
- testSqlApi(s"$substr(f0, f30, f7)", "Thi")
- testSqlApi(s"$substr(f39, 1, 2)", "1世")
- }
- }
-
@Test
def testLPad(): Unit = {
testSqlApi("lpad(f33,1,'??')", "NULL")
@@ -889,127 +848,6 @@ class ScalarFunctionsTest extends ScalarTypesTestBase {
testAllApis("äää".rpad(13, "12345"), "rpad('äää',13,'12345')",
"äää1234512345")
}
- @Test
- def testParseUrl(): Unit = {
-
- // NOTE: parse_url() requires HOST PATH etc. all capitalized
- def testUrl(
- url: String,
- host: String,
- path: String,
- query: String,
- ref: String,
- protocol: String,
- file: String,
- authority: String,
- userInfo: String,
- qv: String): Unit = {
-
- val parts =
- Map(
- "HOST" -> host,
- "PATH" -> path,
- "QUERY" -> query,
- "REF" -> ref,
- "PROTOCOL" -> protocol,
- "FILE" -> file,
- "AUTHORITY" -> authority,
- "USERINFO" -> userInfo)
-
- for ((n, v) <- parts) {
- testAllApis(url.parseUrl(s"$n"), s"parse_url('$url', '$n')", v)
- }
-
- testAllApis(url.parseUrl("QUERY", "query"), s"parse_url('$url', 'QUERY',
'query')", qv)
- }
-
- testUrl(
- "http://[email protected]/path?query=1#Ref",
- "flink.apache.org",
- "/path",
- "query=1",
- "Ref",
- "http",
- "/path?query=1",
- "[email protected]",
- "userinfo",
- "1"
- )
-
- testUrl(
-
"https://use%20r:pas%[email protected]/dir%20/pa%20th.HTML?query=x%20y&q2=2#Ref%20two",
- "example.com",
- "/dir%20/pa%20th.HTML",
- "query=x%20y&q2=2",
- "Ref%20two",
- "https",
- "/dir%20/pa%20th.HTML?query=x%20y&q2=2",
- "use%20r:pas%[email protected]",
- "use%20r:pas%20s",
- "x%20y"
- )
-
- testUrl(
- "http://user:pass@host",
- "host",
- "",
- "NULL",
- "NULL",
- "http",
- "",
- "user:pass@host",
- "user:pass",
- "NULL")
-
- testUrl(
- "http://user:pass@host/",
- "host",
- "/",
- "NULL",
- "NULL",
- "http",
- "/",
- "user:pass@host",
- "user:pass",
- "NULL")
-
- testUrl(
- "http://user:pass@host/?#",
- "host",
- "/",
- "",
- "",
- "http",
- "/?",
- "user:pass@host",
- "user:pass",
- "NULL")
-
- testUrl(
- "http://user:pass@host/file;param?query;p2",
- "host",
- "/file;param",
- "query;p2",
- "NULL",
- "http",
- "/file;param?query;p2",
- "user:pass@host",
- "user:pass",
- "NULL")
-
- testUrl(
- "invalid://user:pass@host/file;param?query;p2",
- "NULL",
- "NULL",
- "NULL",
- "NULL",
- "NULL",
- "NULL",
- "NULL",
- "NULL",
- "NULL")
- }
-
@Test
def testRepeat(): Unit = {
testAllApis('f0.repeat(1), "REPEAT(f0, 1)", "This is a test String.")
diff --git
a/flink-table/flink-table-runtime/src/main/java/org/apache/flink/table/runtime/functions/SqlFunctionUtils.java
b/flink-table/flink-table-runtime/src/main/java/org/apache/flink/table/runtime/functions/SqlFunctionUtils.java
index 54c45f0a4f1..58dfbaf10b0 100644
---
a/flink-table/flink-table-runtime/src/main/java/org/apache/flink/table/runtime/functions/SqlFunctionUtils.java
+++
b/flink-table/flink-table-runtime/src/main/java/org/apache/flink/table/runtime/functions/SqlFunctionUtils.java
@@ -603,7 +603,6 @@ public class SqlFunctionUtils {
try {
url = URL_CACHE.get(urlStr);
} catch (Exception e) {
- LOG.error("Parse URL error: " + urlStr, e);
return null;
}
if ("HOST".equals(partToExtract)) {
@@ -666,16 +665,9 @@ public class SqlFunctionUtils {
public static String subString(String str, long start, long len) {
if (len < 0) {
- LOG.error(
- "len of 'substring(str, start, len)' must be >= 0 and Int
type, but len = {}",
- len);
return null;
}
if (len > Integer.MAX_VALUE || start > Integer.MAX_VALUE) {
- LOG.error(
- "len or start of 'substring(str, start, len)' must be Int
type, but len = {}, start = {}",
- len,
- start);
return null;
}
int length = (int) len;