ccl125 commented on code in PR #66050:
URL: https://github.com/apache/doris/pull/66050#discussion_r3680675977


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RegexpExtractAll.java:
##########
@@ -61,7 +74,7 @@ private RegexpExtractAll(ScalarFunctionParams functionParams) 
{
      */
     @Override
     public RegexpExtractAll withChildren(List<Expression> children) {
-        Preconditions.checkArgument(children.size() == 2);
+        Preconditions.checkArgument(children.size() == 2 || children.size() == 
3);

Review Comment:
   Update: the design changed based on the rolling-upgrade feedback below — the 
FE no longer pads a default index, so a node can legitimately have 2 or 3 
children and the assertion stays `2 || 3`. The BE now accepts both arities.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RegexpExtractAllArray.java:
##########
@@ -64,7 +77,7 @@ private RegexpExtractAllArray(ScalarFunctionParams 
functionParams) {
      */
     @Override
     public RegexpExtractAllArray withChildren(List<Expression> children) {
-        Preconditions.checkArgument(children.size() == 2);
+        Preconditions.checkArgument(children.size() == 2 || children.size() == 
3);

Review Comment:
   Same as above — reverted to `2 || 3` since the FE no longer normalizes to 3 
arguments.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RegexpExtractAllArray.java:
##########
@@ -38,20 +39,32 @@
  * Returns all matches of a regex pattern as an Array&lt;String&gt; instead of 
a string-formatted array.
  */
 public class RegexpExtractAllArray extends ScalarFunction
-        implements BinaryExpression, ExplicitlyCastableSignature, 
AlwaysNullable, PropagateNullLiteral {
+        implements ExplicitlyCastableSignature, AlwaysNullable, 
PropagateNullLiteral {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             FunctionSignature.ret(ArrayType.of(VarcharType.SYSTEM_DEFAULT))
                     .args(VarcharType.SYSTEM_DEFAULT, 
VarcharType.SYSTEM_DEFAULT),
             FunctionSignature.ret(ArrayType.of(StringType.INSTANCE))
-                    .args(StringType.INSTANCE, StringType.INSTANCE)
+                    .args(StringType.INSTANCE, StringType.INSTANCE),
+            FunctionSignature.ret(ArrayType.of(VarcharType.SYSTEM_DEFAULT))

Review Comment:
   Good catch, thanks! Reworked in d387667: the FE no longer pads, and the BE 
now registers both a 2-arg and a 3-arg variadic form (mirroring 
regexp_replace's ThreeParamTypes/FourParamTypes), so an old FE keeps working 
against a new BE during rolling upgrades.



##########
be/src/exprs/function/function_regexp.cpp:
##########
@@ -136,13 +136,17 @@ struct RegexpExtractEngine {
         return false;
     }
 
-    // Match all occurrences and extract the first capturing group
-    void match_all_and_extract(const char* data, size_t size,
+    // Match all occurrences and extract the capturing group with the given 
index.
+    // index 0 means the whole match, 1 means the first capturing group (the 
default), and so on.
+    void match_all_and_extract(const char* data, size_t size, int index,
                                std::vector<std::string>& results) const {
+        if (index < 0) {
+            return;
+        }
         if (is_re2()) {
             int max_matches = 1 + re2_regex->NumberOfCapturingGroups();
-            if (max_matches < 2) {
-                return; // No capturing groups
+            if (index >= max_matches) {

Review Comment:
   Done — the index contract now matches Spark: an index outside [0, 
number_of_capturing_groups] fails with InvalidArgument, with the valid range in 
the message.



##########
be/src/exprs/function/function_regexp.cpp:
##########
@@ -159,9 +163,9 @@ struct RegexpExtractEngine {
                     pos += 1;
                     continue;
                 }
-                // Extract first capturing group
-                if (matches.size() > 1 && !matches[1].empty()) {
-                    results.emplace_back(matches[1].data(), matches[1].size());
+                // Extract the capturing group with the given index
+                if (static_cast<size_t>(index) < matches.size() && 
!matches[index].empty()) {

Review Comment:
   Done — non-participating groups now contribute empty strings instead of 
being skipped (your `(a)|(b)` group-2 example is covered in the unit tests).



##########
be/src/exprs/function/function_regexp.cpp:
##########
@@ -174,8 +178,8 @@ struct RegexpExtractEngine {
             boost::match_results<const char*> matches;
 
             while (boost::regex_search(search_start, search_end, matches, 
*boost_regex)) {
-                if (matches.size() > 1 && matches[1].matched) {
-                    results.emplace_back(matches[1].str());
+                if (static_cast<size_t>(index) < matches.size() && 
matches[index].matched) {

Review Comment:
   Done, both the re2 and the boost path keep empty groups now.



##########
regression-test/suites/query_p0/sql_functions/string_functions/test_string_function_regexp.groovy:
##########
@@ -255,4 +255,11 @@ suite("test_string_function_regexp") {
 
     qt_sql_field4 "SELECT FIELD('21','2130', '2131', '21');"
     qt_sql_field5 "SELECT FIELD(21, 2130, 21, 2131);"
+
+    qt_sql_regexp_extract_all_group0 "select 
regexp_extract_all('x=a3&x=18abc&x=2&y=3&x=4&x=17bcd', 'x=([0-9]+)([a-z]+)', 
0);"
+    qt_sql_regexp_extract_all_group2 "select 
regexp_extract_all('x=a3&x=18abc&x=2&y=3&x=4&x=17bcd', 'x=([0-9]+)([a-z]+)', 
2);"
+    qt_sql_regexp_extract_all_group_negative "select regexp_extract_all('abc', 
'(b)', -1);"
+    qt_sql_regexp_extract_all_array_group0 "select 
regexp_extract_all_array('x=a3&x=18abc&x=2&y=3&x=4&x=17bcd', 
'x=([0-9]+)([a-z]+)', 0);"
+    qt_sql_regexp_extract_all_array_group2 "select 
regexp_extract_all_array('x=a3&x=18abc&x=2&y=3&x=4&x=17bcd', 
'x=([0-9]+)([a-z]+)', 2);"
+    qt_sql_regexp_extract_all_array_group_out_of_range "select 
regexp_extract_all_array('hitdecisiondlist', '(i)(.*?)(e)', 3);"

Review Comment:
   Expanded: column input (three group indexes over the test table), NULL 
literals for string/pattern/index, illegal indexes via exception blocks, and 
the non-participating-group case.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to